据我了解,旧的 JMM 实现惰性单调的 DCL(双重检查锁定)技巧已被破坏,但我认为新的 JMM 和 volatile 字段已修复它......
但是在 this不错的文章,显然足够新,可以引用新的和旧的 JMM 以及 DCL 中的 volatile 字段,指出它仍然损坏......
我到处读到它已修复,然后我发现了这一点...有人能说最后它是否损坏了?
我的理解是,通过 volatile 保证关系之前发生并有效地发出 membar 解决问题,并且 DCL 现在有效......尽管我同意静态惰性初始化更可取并且更容易理解......
最佳答案
Here and there i read that it is fixed then i discover this... Can someone just say finally is it broken or not?
这取决于你所说的“它”是什么意思。
如果您问是否可以使用 volatile 执行 DCL,那么答案是肯定的,在 Java 5 之后。(volatile
的原始语义没有明确定义,这意味着使用 > volatile
不是 Java 5 之前的修复。)
如果您问是否可以在没有 volatile 的情况下执行 DCL,那么答案是否定的。Java 5 内存模型更改不会“修复”使用非 volatile 实例的 DCL 的原始 Java 实现
变量。
如果您问对于延迟初始化的单例使用 DCL 是否仍然是一个好主意,那么答案是否定的。(在我看来):
有更好的方法来实现延迟初始化的单例。使用
enum
就是其中之一。由于 DCL 习惯用法仍然容易出错且不易理解1,因此最好避免使用它。
同步性能的改进很大程度上消除了对 DCL 的需求。
Enum and static init will initialize the singletone on class load (correct me if i'm mistaken).
我认为你错了。类初始化也是惰性的。除非你强制,否则它不会在类加载时发生;例如通过使用 3-arg overload Class.forName
。 JLS 12.4.1列出确定何时发生的规则。
结果是,您可以确保基于枚举的单例的初始化是延迟发生的,并且肯定会安全地完成。
顺便说一句,延迟初始化的硬性要求对我来说暗示了您的应用程序设计中存在问题。至少,它引入了一个脆弱点……无论延迟初始化是如何实现的。
<小时/>1 - 如果“普通 Joe 程序员”不理解 DCL 的复杂性,那么在他可能需要维护的代码中使用 DCL 是一个坏主意。你比普通的乔程序员聪明这一事实是没有意义的。
关于java - DCL 还坏吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59159302/