首页 > 科技 > 你知道单例模式(双重检查加锁)为什么加 volatile关键字吗?

你知道单例模式(双重检查加锁)为什么加 volatile关键字吗?



单例模式的实现

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

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


多线程不安全的原因

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

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


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

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

memory=allocate();//1.分配对象内存空间instance(memory);//2.初始化对象instance=memory;//3.设置instance指向刚分配的内存地址,此时instance!=null

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

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

多线程执行结果如下:


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

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

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

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

问题。


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

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

本文来自投稿,不代表本人立场,如若转载,请注明出处:http://www.souzhinan.com/kj/304369.html