单例模式双重校验_面试官:你知道双重加锁单例模式为什么加volatile关键字吗?...

单例模式的实现

dc780de3ae9d2da992b09c7f35e1d2f5.png

上面代码是一个经典的单例的双重监测的代码,这段代码在单线程环境下并没有什么问题,

但如果在是多线程环境下就可能出现线程安全问题。

多线程不安全的原因

上面代码不安全的原因如下:

当某一个线程执行到第一次监测,读取到的instance不为null时,

instance 的引用对象可能没有完全初始化。

因为 instance =new Singleton(); 可以分为以下三个步骤:

(1) memory=allocate();//1.分配对象内存空间

(2) instance(memory);//2.初始化对象

(3) instance=memory;//3.设置instance指向刚分配的内存地址,此时instance!=null

上面的 2 和 3有可能被重排序:如下

(1) memory=allocate();//1.分配对象内存空间

(2) instance=memory;//3.设置instance指向刚分配的内存地址,此时instance!=null,//但是对象还没有初始化完成!

i(3) nstance(memory);//2.初始化对象

多线程执行结果如下:

340fcdbd07a6663d0bc1430edddb4005.png

由于步骤2和步骤3 不存在数据依赖 关系,而且无论重排序前还是重排序后的执行结果在单线程环境下

是没有改变的,因此这种优化是允许的。但是指令重排只会保证串行语义的执行的一致性(单线程),但并

不关心多线程间的语义一致性。

所以当一条线程访问instance 不为null时,由于 instance 实例未必已初始化完成,也就造成了线程安全

问题。

怎样解决多线程下存在的问题

我们使用 volatile 禁止 instance变量被执行指令重排优化即可:

f942215ca8aea349d7b4155fd104c1fe.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值