DCL单例模式为什么要用volatile
请解释双重检查锁定(DCL)单例模式中volatile关键字的作用,以及不用volatile可能引发的空指针问题。
回答
屠龙少年
DCL代码:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
为什么需要volatile:
instance = new Singleton()在JVM中分为三步:- 分配内存空间。
- 初始化对象(调用构造方法)。
- 将instance引用指向分配的内存地址。
- 指令重排序:步骤2和3可能被重排序(步骤3先于步骤2执行)。
- 线程A执行完步骤3(引用已赋值)但步骤2未完成时,线程B检查instance != null返回true,直接使用instance,但对象还没初始化完成,访问成员变量返回默认值(0/null),导致空指针异常。
volatile作用:
- volatile禁止步骤2和3的重排序。
- 保证instance的可见性(其他线程立即可见最新的引用值)。
替代方案:
- 静态内部类(推荐)。
- 枚举单例(最安全)。