DCL还在坏吗?

时间:2015-06-25 13:10:46

标签: java concurrency singleton java-memory-model

据我所知,对于旧的JMM,实现懒单线的DCL(双重检查锁定)技巧被打破了,但我认为它是用新的JMM和易失性字段修复的......

然而在this好的文章中,显然是新的,需要在DCL中引用新的和旧的JMM和volatile字段,它仍然被打破......

在这里和那里我读到它已被修复然后我发现了这个...有人可以说最后它是否已损坏?

我的理解是,挥发性保证关系之前的hapens并且有效地发布了membar解决问题并且DCL现在有效...尽管我同意静态懒惰初始化更容易理解...

2 个答案:

答案 0 :(得分:10)

  

在这里和那里我读到它已被修复然后我发现了这个...有人可以说最后它是否已损坏?

这取决于你的意思"它"。

如果您问是否可以使用volatile执行DCL,则答案为是,发布Java 5.(volatile的原始语义未明确定义,这意味着使用volatile在Java 5之前没有修复。)

如果您在询问是否可以在没有易失性的情况下进行DCL,那么答案就是“否”.Java 5内存模型的更改不会修复"具有非易失性instance变量的DCL的原始Java实现。

如果你问是否仍然使用DCL进行懒惰的初始化单例,那么答案是否定的(在我看来):

  • 有更好的方法来实现一个懒惰的初始化单例。使用enum就是其中之一。

  • 由于DCL习语仍然容易出错并且不太清楚 1 ,因此最好避免使用它。

  • 同步性能的提升在很大程度上消除了对DCL的需求。

  

枚举和静态初始化将在类加载时初始化单线态(如果我错了,请更正我)。

我认为你错了。类初始化也很懒惰。除非你强迫它,否则它不会在课堂加载时发生;例如使用Class.forName的{​​{3}}。 3-arg overload列出了确定何时发生的规则。

结果是你可以确保基于枚举的单例的初始化是懒散的,并且它肯定会安全地完成。

另外,懒惰初始化的硬性要求提示我应用程序设计中存在问题。至少,它引入了一个脆弱点...无论如何实现延迟初始化。

1 - 如果一个普通的Joe程序员"我不了解DCL的复杂性,因此在他可能需要维护的代码中使用DCL是一个坏主意。事实上,你比普通的Joe程序员更聪明。

答案 1 :(得分:4)

它已在Java 5中修复。

然而这些天来,"正确" (即最简单的方法)是使用枚举进行延迟初始化。

public enum Singleton {
    INSTANCE;

    // No need for a getInstance() method
    //public static Singleton getInstance() {
    //    return INSTANCE;
    //}
    // Add methods to your liking
}