线程局部初始化
ThreadLocal initialization
我见过的每个 ThreadLocal 示例 returns 一个不能动态设置的值,就像这个带有 SimpleDateFormat 的示例一样,每次总是 returns 相同的 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);
}
}
但是,如果我不想使用系统属性,而是想在创建 class 时提供必要的信息怎么办。我怎么做。一切都是静态的,所以我不能使用构造函数。
我不喜欢系统 属性 方法的原因有很多。一方面,我不希望 class 了解有关其周围环境的信息,例如应该阅读一个系统 属性。它应该尽可能简单,并注入所有依赖项。例如,我认为这种编码方式提高了可测试性。
最终解
格式通过调用 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);
}
}
因为你不使用 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
of 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
的所有实例全局设置格式 ,如果它是不是这样,你应该使用这个:
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);
}
}
使用这种方法,您可以注入格式,这是一种更加面向对象的方法。
我见过的每个 ThreadLocal 示例 returns 一个不能动态设置的值,就像这个带有 SimpleDateFormat 的示例一样,每次总是 returns 相同的 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);
}
}
但是,如果我不想使用系统属性,而是想在创建 class 时提供必要的信息怎么办。我怎么做。一切都是静态的,所以我不能使用构造函数。
我不喜欢系统 属性 方法的原因有很多。一方面,我不希望 class 了解有关其周围环境的信息,例如应该阅读一个系统 属性。它应该尽可能简单,并注入所有依赖项。例如,我认为这种编码方式提高了可测试性。
最终解
格式通过调用 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);
}
}
因为你不使用 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
of 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
的所有实例全局设置格式 ,如果它是不是这样,你应该使用这个:
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);
}
}
使用这种方法,您可以注入格式,这是一种更加面向对象的方法。