You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

未用volatile与全方法同步的双重检查锁单例是否线程安全?

为什么你的双重检查锁单例不是线程安全的

你好呀!你的这个双重检查锁实现确实存在线程安全问题,核心原因和Java对象初始化时的指令重排序有关,咱们来一步步拆解:

问题根源:对象初始化的指令重排序

当执行new MySingleton()时,JVM实际会做三件事:

    1. 为MySingleton对象分配内存空间
    1. 调用构造函数,初始化对象的成员变量
    1. 将mySingleton引用指向刚分配的内存地址

为了优化执行效率,JVM允许在不影响单线程执行结果的前提下对这三个步骤进行重排序。也就是说,实际执行顺序可能变成:1 → 3 → 2。这时候就会出现线程安全隐患。

线程不安全的具体场景

假设现在有两个线程A和B同时调用getInstance():

  • 线程A进入第一个if(mySingleton == null)判断,发现引用为空,进入同步代码块
  • 线程A执行new MySingleton(),JVM做了指令重排序:先把mySingleton引用指向内存地址(步骤3),但还没完成对象初始化(步骤2)
  • 这时候线程B进入第一个if(mySingleton == null)判断,发现mySingleton已经不为空(因为指向了内存地址),直接返回这个未完全初始化的对象
  • 线程B尝试使用这个对象时,就会遇到各种问题:比如成员变量还是默认值、抛出NullPointerException,或者其他不符合预期的行为

如何修复?加上volatile关键字

volatile关键字有两个关键作用:

  • 禁止JVM对该变量相关的指令进行重排序
  • 保证变量的可见性(一个线程对变量的修改,其他线程能立刻看到)

修正后的代码如下:

public class MySingleton {
    // 加上volatile关键字
    private static volatile MySingleton mySingleton;

    public static MySingleton getInstance() {
        if(mySingleton == null) {
            synchronized(MySingleton.class) {
                if(mySingleton == null) {
                    MySingleton temp = new MySingleton();
                    mySingleton = temp;
                }
            }
        }
        return mySingleton;
    }
}

加上volatile后,JVM就不会对new MySingleton()的初始化步骤进行重排序,确保线程看到的mySingleton要么是null,要么是完全初始化完成的对象,这样双重检查锁就能保证线程安全了。

内容的提问来源于stack exchange,提问作者Batman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:07:06