这是一个线程安全的singleton:
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
我不明白他为什么要这么做volatile,如果他已经被锁定了Singleton.class。它能救你什么?
在 Java 中创建对象的操作不是原子的。
考虑具有对象创建操作和两个线程的(一种可能的)示例:
Поток AgetInstance()此时进入方法instance == null并进入同步块,其中它也instance == null开始创建对象Singleton。首先,为对象分配内存,然后使用分配的内存区域的引用初始化该对象。此时,他Поток B进入方法并getInstance()看到instance != null他开始使用一个已经存在但尚未构造的对象(因为它的字段尚未初始化)。将字段声明
instance为volatile( JDK 5+ )会在初始化对象instanceПотоком A和返回对象之间建立先行关系instanceПотоку B。换句话说,声明一个字段
instance保证volatile它将поток В读取一个已经完全构造好的对象instance。更新。来自@Roman 的评论,使用的另一个原因
volatile:声明的变量永远不会缓存到线程的内存中,即它
volatile在任何线程中的任何时间都将具有相同的(实际)值(如果一个线程更改其值,那么该值将立即在其他线程中可用)。因为比较阅读
发生在同步块之外,副作用可能已经是,例如,在堆中创建的对象,但尚未调用构造函数,或缓存的空值。JDK 5.0 及更高版本的内存模型需要这样做,以便多线程程序的行为是可预测的。