【问题标题】:Unexpected behavior of static member in multithread processing多线程处理中静态成员的意外行为
【发布时间】:2014-09-17 08:09:55
【问题描述】:

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

public class A implements Comparable<A>
{

    public static final SimpleDateFormat INPUT_SDF  = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss", Locale.US);

    ...

    public void setDate(String string) throws ParseException
    {
        synchronized (INPUT_SDF)
        {
            date = INPUT_SDF.parse(string);
        }
    }

}

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

【问题讨论】:

  • 如果您没有被 Java 8 之前的版本卡住,那么我强烈建议您使用新的 Date API,它包括线程安全的解析器和格式化程序。

标签: java multithreading static-members


【解决方案1】:

不将字段设置为 static final 不足以使代码线程安全。它仅使对对象线程的引用分配是安全的,从而确保其他线程将在该字段中看到相同的对象引用。它不会使存储在字段中(分配后)线程安全的对象中存储的数据发生突变。这是 SimpleDataFormat 的问题。

来自SimpleDateFormat的文档。

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

如果 SimpleDateFormat 是无状态的,或者被写入使其状态是线程安全的,那么是的,静态 final 就足以成为线程安全的。

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

【讨论】:

    【解决方案2】:

    创建字段static final 只会使reference 线程安全;它不会同步对被引用对象的访问。

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

    设置static final 字段只是保证所有线程都会看到相同的引用值。


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

    如果您想安全地重用 SimpleDateFormat 的实例,请考虑使用 ThreadLocal 方便地允许为每个线程使用单独的实例,这样您就可以删除同步:

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

    【讨论】:

    • 非常感谢波西米亚人,我感受到了瓶颈效应但并不知道。请允许我纠正您示例代码中的一个小错误:您需要将字段格式的最后一个“}”替换为“;”。
    • @Bludwarf 确实-感谢您抓住了这一点。为了我的辩护,我在火车上用我的 iPhone 直接把那个代码翻到了答案中。
    【解决方案3】:

    SimpleDateFormat 类未同步。

    您可以查看此question 了解更多信息。 希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-09
      • 1970-01-01
      相关资源
      最近更新 更多