DCL还坏吗?
Is DCL still broken?
据我对旧 JMM 的了解,实现惰性单例的 DCL(双重检查锁定)技巧已被破坏,但我认为它已通过新 JMM 和易失性字段修复...
但是在 this 一篇不错的文章中,它显然是新的,足以引用新旧 JMM 和 DCL 中的 volatile 字段,指出它仍然是坏的...
我在这里和那里看到它是固定的然后我发现了这个...有人能说最后它坏了吗?
我的理解是,通过 volatile 保证关系之前发生的事情并有效地发布一个 membar 解决了问题,DCL 现在有效...虽然我同意 static lazy init 更可取并且更容易理解...
已在 Java 5.
中修复
然而现在 "correct"(即最简单的)方法是使用枚举进行延迟初始化。
public enum Singleton {
INSTANCE;
// No need for a getInstance() method
//public static Singleton getInstance() {
// return INSTANCE;
//}
// Add methods to your liking
}
Here and there i read that it is fixed then i discover this... Can someone just say finally is it broken or not?
这取决于你所说的 "it" 是什么意思。
如果你问是否可以使用 volatile 做 DCL,那么答案是肯定的,post Java 5.(volatile
的原始语义定义不明确,这意味着使用 volatile
不是解决方法,pre Java 5.)
如果您问是否可以在没有 volatile 的情况下执行 DCL,那么答案是否定的。Java 5 内存模型更改不会 "fix" 最初的 Java 实现具有非易失性 instance
变量的 DCL。
如果您问将 DCL 用于惰性初始化单例是否仍然是个好主意,那么答案是否定的。(在我看来):
有更好的方法来实现延迟初始化的单例。使用 enum
就是其中之一。
既然DCL惯用语仍然容易出错且理解不佳1,最好避免使用。
同步性能的改进在很大程度上消除了对 DCL 的需求。
Enum and static init will initialize the singletone on class load (correct me if i'm mistaken).
我认为你错了。 Class 初始化也偷懒了。它不会在 class 加载时发生,除非你强制它;例如通过使用 3-arg overload of Class.forName
. JLS 12.4.1 设置确定何时发生的规则。
结果是您可以确保基于枚举的单例的初始化是延迟发生的,并且肯定会安全地完成。
顺便说一句,延迟初始化的硬性要求让我想到您的应用程序设计中存在问题。至少,它引入了一个脆弱点......无论惰性初始化如何实现。
1 - 如果 "average Joe programmer" 不理解 DCL 的复杂性,那么在他可能需要维护的代码中使用 DCL 是个坏主意。你比一般的 Joe 程序员更聪明这一事实没有实际意义。
据我对旧 JMM 的了解,实现惰性单例的 DCL(双重检查锁定)技巧已被破坏,但我认为它已通过新 JMM 和易失性字段修复...
但是在 this 一篇不错的文章中,它显然是新的,足以引用新旧 JMM 和 DCL 中的 volatile 字段,指出它仍然是坏的...
我在这里和那里看到它是固定的然后我发现了这个...有人能说最后它坏了吗?
我的理解是,通过 volatile 保证关系之前发生的事情并有效地发布一个 membar 解决了问题,DCL 现在有效...虽然我同意 static lazy init 更可取并且更容易理解...
已在 Java 5.
中修复然而现在 "correct"(即最简单的)方法是使用枚举进行延迟初始化。
public enum Singleton {
INSTANCE;
// No need for a getInstance() method
//public static Singleton getInstance() {
// return INSTANCE;
//}
// Add methods to your liking
}
Here and there i read that it is fixed then i discover this... Can someone just say finally is it broken or not?
这取决于你所说的 "it" 是什么意思。
如果你问是否可以使用 volatile 做 DCL,那么答案是肯定的,post Java 5.(volatile
的原始语义定义不明确,这意味着使用 volatile
不是解决方法,pre Java 5.)
如果您问是否可以在没有 volatile 的情况下执行 DCL,那么答案是否定的。Java 5 内存模型更改不会 "fix" 最初的 Java 实现具有非易失性 instance
变量的 DCL。
如果您问将 DCL 用于惰性初始化单例是否仍然是个好主意,那么答案是否定的。(在我看来):
有更好的方法来实现延迟初始化的单例。使用
enum
就是其中之一。既然DCL惯用语仍然容易出错且理解不佳1,最好避免使用。
同步性能的改进在很大程度上消除了对 DCL 的需求。
Enum and static init will initialize the singletone on class load (correct me if i'm mistaken).
我认为你错了。 Class 初始化也偷懒了。它不会在 class 加载时发生,除非你强制它;例如通过使用 3-arg overload of Class.forName
. JLS 12.4.1 设置确定何时发生的规则。
结果是您可以确保基于枚举的单例的初始化是延迟发生的,并且肯定会安全地完成。
顺便说一句,延迟初始化的硬性要求让我想到您的应用程序设计中存在问题。至少,它引入了一个脆弱点......无论惰性初始化如何实现。
1 - 如果 "average Joe programmer" 不理解 DCL 的复杂性,那么在他可能需要维护的代码中使用 DCL 是个坏主意。你比一般的 Joe 程序员更聪明这一事实没有实际意义。