据我了解,旧的 JMM 实现惰性单调的 DCL(双重检查锁定)技巧已被破坏,但我认为新的 JMM 和易失性字段已修复它......
然而在this不错的文章,显然足够新,可以引用新旧 JMM 和 DCL 中的易失性字段,指出它仍然损坏......
我到处读到它已修复,然后我发现了这一点...有人可以说最后它是否损坏了?
我的理解是,通过 volatile 保证关系发生之前的情况并有效地发出 membar 解决问题,并且 DCL 现在有效......尽管我同意静态惰性初始化更可取并且更容易理解......
我到处读到它已修复,然后我发现了这一点...有人可以说最后它是否损坏了?
这取决于你所说的“它”是什么意思。
如果您问是否可以使用 volatile 执行 DCL,那么答案是肯定的,在 Java 5 之后。(原始语义volatile
没有明确定义,这意味着使用volatile
在 Java 5 之前没有修复。)
如果您询问是否可以在没有 易失性的情况下执行 DCL,那么答案是否定的。Java 5 内存模型更改不会“修复”具有非易失性的 DCL 的原始 Java 实现instance
多变的。
如果您问对于延迟初始化的单例使用 DCL 是否仍然是一个好主意,那么答案是否定的。(在我看来):
有更好的方法来实现延迟初始化的单例。使用enum
是其中之一。
Since the DCL idiom is still error prone and not well understood1, it is better to avoid it.
同步性能的改进很大程度上消除了对 DCL 的需求。
枚举和静态初始化将在类加载时初始化单例(如果我错了,请纠正我)。
我想,那你就错了。类初始化也是惰性的。除非你强制,否则它不会在类加载时发生;例如通过使用3-arg 过载 of Class.forName
. JLS 12.4.1规定了确定何时发生的规则。
结果是,您可以确保基于枚举的单例的初始化是延迟发生的,并且肯定会安全地完成。
顺便说一句,延迟初始化的硬性要求对我来说表明您的应用程序设计中存在问题。至少,它引入了一个脆弱点……无论延迟初始化是如何实现的。
1 - If an "average Joe programmer" doesn't understand the intricacies of DCL, then it is a bad idea to use DCL in code that he might need to maintain. The fact that you are smarter than the average Joe programmer is moot.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)