DCL还在坏吗?

vac*_*ach 2 java concurrency singleton java-memory-model

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

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

在这里和那里我读到它是固定的然后我发现这个...有人可以说最后它是否破碎?

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

Ste*_*n C 10

在这里和那里我读到它是固定的然后我发现这个...有人可以说最后它是否破碎?

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

如果你问你是否可以使用volatile执行DCL,那么答案是肯定的,发布Java 5.(原始语义volatile没有很好地定义,这意味着使用a volatile不是修复,在Java 5之前.)

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

如果你问是否使用DCL作为懒惰的初始化单例仍然是一个好主意,那么答案是否定的(在我看来):

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

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

  • 同步性能的改进在很大程度上消除了对DCL的需求.


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

我想,那你就错了.类初始化也很懒惰.除非你强迫它,否则它不会在课堂加载时发生; 例如,通过使用3 -精氨酸过载Class.forName. JLS 12.4.1规定了确定何时发生的规则.

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

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


1 - 如果"普通的Joe程序员"不理解DCL的复杂性,那么在他可能需要维护的代码中使用DCL是一个坏主意.你比一般的Joe程序员聪明的事实是没有实际意义的.


Kay*_*man 5

它在 Java 5 中得到了修复。

然而,如今“正确”(即最简单)的方法是使用枚举进行延迟初始化。

public enum Singleton {
    INSTANCE;

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