为什么在单例类中不能使用双重检查锁来初始化对象
2015-09-18 10:02
183 查看
在网上看到过好多篇文章在说明双重检查锁在多个线程初始化一个单例类时到底为什么不行时在关键位置的描述模棱两可,今天我们就来看一下为什么不能用双重检查锁,问题到底出在了那里?
下面我们直接进入主题,为什么使用双重检查锁,原因是因为在多线程初始化一个单例类时我们要确保得到一个对象,又想再确保一个对象时得到更高的效率,所以就有了双重检查锁,使用双重检查锁初始化对象的代码如下public class DoubleCheckedLocking { //1 private static DoubleCheckedLocking instance; //2 public static DoubleCheckedLocking getInstance() { //3 if (instance == null) { //4:第一次检查 synchronized (DoubleCheckedLocking.class) { //5:加锁 if (instance == null) //6:第二次检查 instance = new DoubleCheckedLocking(); //7:问题的根源出在这里 } //8 } //9 return instance; //10 } //11 }为什么这样是不行的,问题的根源出在第7行(instance = new DoubleCheckedLocking();),创建一个对象可以分解为如下三步:
memory = allocate(); //1:分配对象的内存空间 ctorInstance(memory); //2:初始化对象 instance = memory; //3:设置instance指向刚分配的内存地址上面三行伪代码中的2和3之间,可能会被重排序,2和3之间重排序之后的执行时序如下:
memory = allocate(); //1:分配对象的内存空间 instance = memory; //3:设置instance指向刚分配的内存地址 //注意,此时对象还没有被初始化! ctorInstance(memory); //2:初始化对象重排序不能影响单线程的执行语义,虽然这里2和3进行了重排序,但是只要保证2排在4前面执行,单线程内的执行结果不会被改变
时间 | 线程A | 线程B |
t1 | A1:分配对象的内存空间 | |
t2 | A3:设置instance指向内存空间 | |
t3 | B1:判断instance是否为空 | |
t4 | B2:由于instance不为null,线程B将访问instance引用的对象(而这个时候对象还没有初始化) | |
t5 | A2:初始化对象 | |
t6 | A4:访问instance引用的对象 |
总结,到此为止我们只说明了为什么不可以用双重检查锁来初始化对象
THE END!!!
相关文章推荐
- SharedWorker对象
- 将Docker安装到CentOS或Fedora上
- (转)CentoS 下报的 Requires: perl(:MODULE_COMPAT_5.8.8)
- Linux 动态库搜索路径
- iOS9 对ShareSDK的影响(适配iOS 9必读)
- PHP 获取网上文件内容
- GBDT 提升回归树
- 限制<input>输入框不能输入任何东西的html代码是什么
- LeetCode Compare Version Numbers
- MapReduce工作原理
- Socket高性能IO模型浅析
- 情商高就是说话让人舒服
- 升级xcode7之后原有项目无法连网的解决方案
- python可变集合类型方法
- 9.18, 9.18,...流亡三部曲及其诞生背景
- LeetCode Compare Version Numbers
- 遇到问题??
- 【转】Github入门教程
- 一些不错的开发交流网站
- TF-IDF与余弦相似性的应用(三):自动摘要(转)