让我们看看经典的双重检查
class Foo {
private volatile Foo singleton = null;
public Foo getFooSingleton() {
if (singleton == null) {
synchronized(this) {
if (singleton == null)
singleton = new Foo();
}
}
return singleton;
}
}
易失性modifire保证在所有线程中都能正确看到“singleton”变量的值。但在当前的例子中我真的需要这个吗? 我想不是。所以 - 这就是我看到这个程序以最坏的方式运行的方式 - 当一个线程所做的更改被其他人看不到时。
singleton != null
),进行第二次检查并退出同步部分。因此。即使没有挥发性声明,一切都有效,甚至更好=)
答案 0 :(得分:5)
是的,此处需要volatile
。
关键是在创建Foo
(包括创建对象和执行其构造函数)之间没有memory barrier并在singleton
字段中存储对它的引用其他线程可以观察这些以任意顺序发生的动作。特别地,在第一次检查期间,线程2可以观察指向部分构造的对象的参考。请注意,synchronized
阻止此处无法提供帮助,因为主题2会看到singleton != null
并且根本不会输入它。
使用volatile
确保放置适当的内存屏障(因为Java 5;在以前的版本中,根本无法实现双重检查习惯用法)。
答案 1 :(得分:2)
Java中的DCL问题不是额外同步的代价。真正的问题是没有volatile
修饰符(在Java 5之前)你的线程可以看到构造不正确的singleton
对象。
要清楚。写入singleton
引用并写入singleton
在单线程程序中顺序执行的字段可能在多线程中无序。