Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 线程本地初始化_Java_Initialization_Thread Local - Fatal编程技术网

Java 线程本地初始化

Java 线程本地初始化,java,initialization,thread-local,Java,Initialization,Thread Local,我看到的每个ThreadLocal示例都会返回一个无法动态设置的值,就像下面的SimpleDataFormat示例一样,它每次都会返回相同的SimpleDataFormat: public class Foo { // SimpleDateFormat is not thread-safe, so give one to each thread private static final ThreadLocal<SimpleDateFormat> formatter =

我看到的每个ThreadLocal示例都会返回一个无法动态设置的值,就像下面的SimpleDataFormat示例一样,它每次都会返回相同的SimpleDataFormat:

public class Foo
{
    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            return new SimpleDateFormat("yyyyMMdd HHmm");
        }
    };

    public String formatIt(Date date)
    {
        return formatter.get().format(date);
    }
}
公共类Foo
{
//SimpleDataFormat不是线程安全的,因此为每个线程提供一个
私有静态最终ThreadLocal格式化程序=新ThreadLocal(){
@凌驾
受保护的SimpleDataFormat初始值()
{
返回新的SimpleDataFormat(“yyyyMMdd HHmm”);
}
};
公共字符串格式(日期)
{
返回格式化程序.get().format(日期);
}
}
但假设我希望能够配置返回的值。一种方法是使用如下系统属性:

public class Foo
{
    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            String dateFormat = System.getProperty("date.format");
            return new SimpleDateFormat(dateFormat);
        }
    };

    public String formatIt(Date date)
    {
        return formatter.get().format(date);
    }
}
public class Foo {
    private static volatile String FORMAT = "yyyyMMdd HHmm";

    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = 
        new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat(FORMAT);
        }
    };

    public static void setFormat(String format) {
        FORMAT = format;
    }
    ...
}
公共类Foo
{
//SimpleDataFormat不是线程安全的,因此为每个线程提供一个
私有静态最终ThreadLocal格式化程序=新ThreadLocal(){
@凌驾
受保护的SimpleDataFormat初始值()
{
字符串dateFormat=System.getProperty(“date.format”);
返回新的SimpleDataFormat(日期格式);
}
};
公共字符串格式(日期)
{
返回格式化程序.get().format(日期);
}
}
但是,如果我不想使用系统属性,而是想在创建类时为它提供必要的信息,该怎么办呢。我该怎么做呢。一切都是静态的,所以我不能使用构造函数

我不喜欢系统属性方法的原因有很多。首先,我不想让类知道它周围的东西,比如有一个应该读取的系统属性。它应该尽可能简单,并注入所有依赖项。例如,我认为这种编码方式提高了可测试性

最终解决方案

通过调用setFormat和对format的所有调用设置一次格式,然后使用相同的格式

public class Foo {

    private static volatile String FORMAT;

    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>() {
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat(FORMAT);
        }
    };

    /**
     * Set the format. Must be called before {@link #formatIt(Date)}. Must only be called once.
     * 
     * @param format
     *            a format, e.g. "yyyyMMdd HHmm".
     * @throws IllegalStateException
     *             if this method has already been called.
     */
    public static void setFormat(String format) {
        if (Foo.FORMAT != null) {
            throw new IllegalStateException("Format has already been set");
        }
        FORMAT = format;
    }

    /**
     * @return the formatted date.
     * @throws IllegalStateException
     *             if this method is called before {@link #setFormat(String)} has been called.
     */
    public static String formatIt(Date date) {
        if (Foo.FORMAT == null) {
            throw new IllegalStateException("Format has not been set");
        }
        return formatter.get().format(date);
    }

}
公共类Foo{
私有静态可变字符串格式;
私有静态最终ThreadLocal格式化程序=新ThreadLocal(){
@凌驾
受保护的SimpleDataFormat初始值(){
返回新的SimpleDataFormat(格式);
}
};
/**
*设置格式。必须在{@link#formatt(Date)}之前调用。只能调用一次。
* 
*@param格式
*格式,例如“yyyyMMdd HHmm”。
*@抛出非法状态异常
*如果已调用此方法。
*/
公共静态void setFormat(字符串格式){
如果(Foo.FORMAT!=null){
抛出新的IllegalStateException(“格式已设置”);
}
格式=格式;
}
/**
*@返回格式化日期。
*@抛出非法状态异常
*如果在调用{@link#setFormat(String)}之前调用此方法。
*/
公共静态字符串formatt(日期){
if(Foo.FORMAT==null){
抛出新的IllegalStateException(“未设置格式”);
}
返回格式化程序.get().format(日期);
}
}

由于您不使用DI框架,对我来说,唯一的方法是添加一个
静态
setter,允许动态更改您的格式,如下所示:

public class Foo
{
    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            String dateFormat = System.getProperty("date.format");
            return new SimpleDateFormat(dateFormat);
        }
    };

    public String formatIt(Date date)
    {
        return formatter.get().format(date);
    }
}
public class Foo {
    private static volatile String FORMAT = "yyyyMMdd HHmm";

    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = 
        new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat(FORMAT);
        }
    };

    public static void setFormat(String format) {
        FORMAT = format;
    }
    ...
}
正如您所见,
ThreadLocal
不再需要,因为
DateTimeFormatter
是线程安全的

NB:我假设您需要为
Foo
的所有实例全局设置格式,如果不是这样,您应该使用以下方法:

public class Foo {

    private volatile DateTimeFormatter formatter = 
        DateTimeFormat.forPattern("yyyyMMdd HHmm");;

    public String formatIt(Date date) {
        return formatter.print(date.getTime());
    }

    public void setFormat(String format) {
        this.formatter = DateTimeFormat.forPattern(format);
    }
}

通过这种方法,您可以注入格式,这是一种更加面向对象的方法。

由于您不使用DI框架,对我来说,唯一的方法是添加一个
静态
setter,允许动态更改您的格式,如下所示:

public class Foo
{
    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            String dateFormat = System.getProperty("date.format");
            return new SimpleDateFormat(dateFormat);
        }
    };

    public String formatIt(Date date)
    {
        return formatter.get().format(date);
    }
}
public class Foo {
    private static volatile String FORMAT = "yyyyMMdd HHmm";

    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = 
        new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat(FORMAT);
        }
    };

    public static void setFormat(String format) {
        FORMAT = format;
    }
    ...
}
正如您所见,
ThreadLocal
不再需要,因为
DateTimeFormatter
是线程安全的

NB:我假设您需要为
Foo
的所有实例全局设置格式,如果不是这样,您应该使用以下方法:

public class Foo {

    private volatile DateTimeFormatter formatter = 
        DateTimeFormat.forPattern("yyyyMMdd HHmm");;

    public String formatIt(Date date) {
        return formatter.print(date.getTime());
    }

    public void setFormat(String format) {
        this.formatter = DateTimeFormat.forPattern(format);
    }
}

通过这种方法,您注入了一种更加面向对象的格式。

您使用java 8吗?不,我使用java 1.6.Wy来否决投票?我对此进行了广泛的研究,我是一名经验丰富的程序员。我又不是在学校,只是想让你们帮我做作业。这将用于生产。如果给我否决票的人认为这是一个无关紧要的问题,请提供答案。你使用java 8吗?不,我使用java 1.6.Wy否决票?我对此进行了广泛的研究,我是一名经验丰富的程序员。我又不是在学校,只是想让你们帮我做作业。这将用于生产。如果给我否决票的人认为这是一个无关紧要的问题,请提供一个答案。这实际上要简单得多,我不应该在累的时候考虑threadlocals。@Nicolas感谢你提出的解决方案。然而,这个解决方案与之前由Kayaman提出的解决方案不同吗?哪一个?他提出了两个解决方案“丑陋”的一个:)这个解决方案和这个解决方案之间的区别似乎是您使用volatile关键字,并且他在您第一次调用get()时检查了FORMAT变量是否已实际设置。我只是想知道是什么让他去掉了他的解决方案,说这更简单。它们似乎和我差不多。单例不是惰性创建的,它不容易出错,而且更简单。实际上,这要简单得多,当我累了的时候,我不应该考虑threadlocals。@Nicolas感谢您提出的解决方案。然而,这个解决方案与之前由Kayaman提出的解决方案不同吗?哪一个?他提出了两个解决方案“丑陋”的一个:)这个解决方案和这个解决方案之间的区别似乎是您使用volatile关键字,并且他检查了当您