Java 多线程处理中静态成员的意外行为

Java 多线程处理中静态成员的意外行为,java,multithreading,static-members,Java,Multithreading,Static Members,我已经解决了一个关于随机多线程处理的问题。我很高兴,因为它的工作,但我想知道为什么。下面代码中的故障成员称为INPUT\u SDF。我认为静态最终成员不需要同步块,但当我删除它时,一切都出错了 公共类A实现了可比性 { public static final SimpleDateFormat INPUT_SDF=新的SimpleDateFormat(“EEE-MMM-dd-yyy-HH:mm:ss”,Locale.US); ... 公共void setDate(字符串)引发ParseExcept

我已经解决了一个关于随机多线程处理的问题。我很高兴,因为它的工作,但我想知道为什么。下面代码中的故障成员称为
INPUT\u SDF
。我认为静态最终成员不需要同步块,但当我删除它时,一切都出错了

公共类A实现了可比性
{
public static final SimpleDateFormat INPUT_SDF=新的SimpleDateFormat(“EEE-MMM-dd-yyy-HH:mm:ss”,Locale.US);
...
公共void setDate(字符串)引发ParseException
{
已同步(输入\ SDF)
{
日期=输入\ SDF.parse(字符串);
}
}
}

我对静态最终成员的理解是否错误?或者在我的代码中还有其他不线程安全的东西吗?

不将字段设为静态final不足以使代码线程安全。它只会使引用分配给对象线程是安全的,从而确保其他线程将在该字段中看到相同的对象引用。它不会使存储在字段(赋值后)中的对象中存储的数据的变异成为线程安全的。这就是SimpleDataFormat的问题所在

从的文档中

日期格式不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一种格式,则必须在外部对其进行同步

如果SimpleDataFormat是无状态的,或者编写为使其状态是线程安全的,那么yes static final就足以实现线程安全

实际上,如果希望在线程之间共享SimpleDataFormat的同一实例,则必须首先针对同一监视器同步线程。否则,建议为每个线程创建SimpleDataFormat的新实例,或者根据需要创建新实例,或者使用ThreadLocal或类似机制。

类不同步

你可以看看这个来了解更多信息。
希望有帮助。

创建一个字段
静态final
只会使引用线程安全;它不会同步对引用对象的访问

因为SimpleDataFormat的实例不是线程安全的,如果一个实例被多个线程同时使用,则必须同步对它的访问(就像您所做的那样)

使字段
静态final
只是保证所有线程都会看到相同的引用值


但是,您当前的代码是一个潜在的瓶颈,因为所有线程都必须排队才能使用实例,这可能会产生比每次创建一个新实例更糟糕的性能

如果您想安全地重用SimuleDATA格式的实例,请考虑使用以方便地为每个线程使用单独的实例,这将允许您删除同步:

private static final ThreadLocal<SimpleDateFormat> formats =
    new ThreadLocal<SimpleDateFormat>() {
        @Override protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss", Locale.US);
        }
    };

public void setDate(String string) throws ParseException {
    return formats.get().parse(string);
}
private静态最终线程本地格式=
新ThreadLocal(){
@重写受保护的SimpleDataFormat初始值(){
返回新的SimpleDataFormat(“EEE-MMM-dd-yyy-HH:mm:ss”,Locale.US);
}
};
公共void setDate(字符串)引发ParseException{
返回formats.get().parse(字符串);
}

如果您没有被8之前的Java所困扰,那么我会热情推荐新的Date API,它包括线程安全解析器和格式化程序。多亏了波西米亚人,我感觉到了瓶颈效应,但我并不知道。请允许我更正示例代码中的一个小错误:您需要将字段格式的最后一个“}”替换为“;”@真的,谢谢你抓住了那个。为我辩护,我在火车上用iphone将代码直接输入答案。