Java 线程本地初始化
我看到的每个ThreadLocal示例都会返回一个无法动态设置的值,就像下面的SimpleDataFormat示例一样,它每次都会返回相同的SimpleDataFormat: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 =
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关键字,并且他检查了当您