懒汉式单例模式到底需不需要volatile

最近一直有个疑问,创建线程安全的懒汉式单例模式到底需不需要volatile,为此深究了一下。

首先先写一个不加的情况:

/**
 * @author PanBangLin
 * @version 1.0
 * @date 2022/7/3 11:26
 */
public class SingleTest {

    private static SingleTest SINGLE;

    private SingleTest() {};

    public SingleTest getSINGLE(){
        // double check  lock 双重检查锁
        if(SINGLE == null){ // 第一次判断
            synchronized (SingleTest.class){ 
                if (SINGLE == null){ // 第二次判断
                    SINGLE = new SingleTest();
                }
            }
        }
        return SINGLE;
    }


}

为什么要使用双重检测锁呢?因为在并发的情况下,有可能有多个线程同时符合了第一次判断的情况,进入到了synchronized处等待,等到第一个线程实例化好对象后,将锁释放,后面卡在锁上的线程又会陆续实例化对象,造成重复实例化。
继续回到 volatile 的问题,了解这个问题,需要先明白对象实例化的过程:

	op1:分配内存空间
	op2:初始化对象
	op3:将对象的引用,指向分配的内存

如果发生指令重排

	op1:分配内存空间
	op2:将对象的引用,指向分配的内存
	op3:初始化对象  

那么如果在第一个线程实例化的过程中,后续再有线程进入到了第一次判断不等于null的部分,那么会直接返回这个半实例化的对象,因为这个时候SINGLE 已经不等于null了,但是这个对象是无法使用的,后面这个线程调用的时候就会发生报错。
所以我们需要把这个变量加上 volatile关键字,让其不发生指令重排,以及修改后的值马上同步到主存上去。
最终效果:

/**
 * @author PanBangLin
 * @version 1.0
 * @date 2022/7/3 11:26
 */
public class SingleTest {

    private volatile static SingleTest SINGLE;

    private SingleTest() {};

    public SingleTest getSINGLE(){
        // double check  lock 双重检查锁
        if(SINGLE == null){ // 第一次判断
            synchronized (SingleTest.class){
                if (SINGLE == null){ // 第二次判断
                    SINGLE = new SingleTest();
                }
            }
        }
        return SINGLE;
    }


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值