ThreadLocal初始化

时间:2016-09-23 08:22:36

标签: java initialization thread-local

我见过的ThreadLocal的每个例子都返回一个无法动态设置的值,就像这个使用SimpleDateFormat的例子一样,每次都会返回相同的SimpleDateFormat:

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);
    }
}

但是,我想说我希望能够配置返回的值。一种方法是使用这样的系统属性:

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);
    }
}

但是,如果我不想使用系统属性,而是希望在创建时为类提供必要的信息,那该怎么办呢?我怎么做。一切都是静态的,所以我不能使用构造函数。

我不喜欢系统属性方法的原因很多。首先,我不希望班级知道有关其周围环境的内容,例如应该阅读的系统属性。它应该尽可能简单并注入所有依赖项。我认为这种编码方式可以提高可测试性。

最终解决方案

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

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);
    }

}

1 个答案:

答案 0 :(得分:2)

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

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;
    }
    ...
}

这很难看,但我没有看到更好的方法。

在这个特定的用例中,当您使用Java 6时,我建议使用DateTimeFormatter Joda-Time代替SimpleDateFormat,因为它做同样的事情并且它是线程安全的开箱即用。

以下是您的代码的样子:

public class Foo {

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

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

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

正如您所见,ThreadLocal不再需要DateTimeFormatter,因为Foo是线程安全的。

NB:我认为您需要为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); } } 的所有实例设置全局格式,如果不是这样,您应该使用这样:

from("file:inbox")
  .split().tokenize("\n", 1000).streaming()
     .to("activemq:queue:order");

使用这种方法,您可以注入更多OO方法的格式。