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程序员聪明的事实是没有实际意义的.
它在 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)