多线程下双重检查锁的问题及解决方法
来源:互联网 发布:抽奖程序java 编辑:程序博客网 时间:2024/06/04 18:09
单例模式中有一种实现方式叫双重检查锁,主要是为了更好、更安全的实现单例功能。先来看一下该方法的核心代码:
public class DoubleCheckedLocking{ private static Instance instance; public static Instance getInstance(){ if(instance ==null){ synchronized (DoubleCheckedLocking.class){ if(instance ==null) instance=new Instance(); //① } } return instance; }}
表面上来看,在执行该代码时,先判断instance对象是否为空,为空时再进行初始化对象。即使是在多线程环境下,因为使用了synchronized锁进行代码同步,该方法也仅仅创建一个实例对象。但是,从根本上来说,这样写还是存在一定问题的。问题源头:
上述代码标号为①的代码功能是是创建实例对象,可以分解为如下伪代码步骤:
memory = allocate() ; //分配对象的内存空间ctorInstance(memory); //②初始化对象instance=memory; //③设置instance指向刚分配的内存地址
其中②和③之间,在某些编译器编译时,可能出现重排序(主要是为了代码优化),此时的代码如下:
memory = allocate() ; //分配对象的内存空间instance=memory; //③设置instance指向刚分配的内存地址ctorInstance(memory); //②初始化对象
单线程下执行时序图如下:
多线程下执行时序图:
由于单线程中遵守intra-thread semantics,从而能保证即使②和③交换顺序后其最终结果不变。但是当在多线程情况下,线程B将看到一个还没有被初始化的对象,此时将会出现问题。
解决方案:
1、不允许②和③进行重排序
2、允许②和③进行重排序,但排序之后,不允许其他线程看到。
基于volatile的解决方案
对前面的双重锁实现的延迟初始化方案进行如下修改:
public class DoubleCheckedLocking{ private volatile static Instance instance; public static Instance getInstance(){ if(instance ==null){ synchronized (DoubleCheckedLocking.class){ if(instance ==null) instance=new Instance(); //用volatile修饰,不会再出现重排序 } } return instance; }}使用volatile修饰instance之后,之前的②和③之间的重排序将在多线程环境下被禁止,从而保证了线程安全执行。
注意:这个解决方案需要JDK5或更高版本(因为从JDK5开始使用新的JSR-133内存模型规范,这个规范增强了volatile的语义)
基于类初始化的解决方案
JVM在类的初始化阶段(即在Class被加载后,且被线程使用之前),会执行类的初始化。在执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化。基于这个特性,可以实现另一种线程安全的延迟初始化方案。
public class InstanceFactory { private static class InstanceHolder { public static Instance instance = new Instance(); } public static Instance getInstance() { return InstanceHolder.instance ; //这里将导致InstanceHolder类被初始化 }}
执行的示意图: 该方案的实质是,允许②和③进行重排序,但不允许非构造线程(此处是B线程)“看到”这个重排序。
阅读全文
1 0
- 多线程下双重检查锁的问题及解决方法
- 多线程下双重检查锁的问题及解决方法
- 多线程情况下双重检查锁定问题的分析与优化
- Java单例模式中双重检查锁的问题
- Java单例模式中双重检查锁的问题
- Java单例模式中双重检查锁的问题
- 单例模式双重检查锁问题
- 双重检查锁定及单例模式 双重检查锁定失效的原因!!
- 双重检查锁机制
- 单例模式中的 双重检查锁定(Double-Check Locking ) (多线程下单例模式中的双重检查锁定的实现)
- 单例的各种写法以及双重检查的问题
- 关于双重锁的问题
- Double check 双重锁检查
- 双重检查锁实现的单例模式
- 一个经典的单例模式(双重检查锁)
- Java 单例 双重检查锁的正确姿势
- 双重检查锁定及单例模式
- 双重检查锁定及单例模式
- dubbo处理调用请求涉及缓存问题
- seafile从sqlite迁移到mysql
- String
- Spring基础
- 拓扑范例
- 多线程下双重检查锁的问题及解决方法
- jquery源码学习
- eclipse使用技巧
- LeetCode 70 Climbing Stairs(Python详解及实现)
- ssh 常见问题累积...
- 整理几个Android中面试遇到的,有点模糊的细节
- Ubuntu16.04配置cpu版本Caffe
- ucosII的事件标志组的使用心得
- svn cornerstone错误码