二十二、应用双重锁定检查于单例模式中的问题
2012-08-27 16:18
281 查看
之前在很多单例类中看到双重锁定检查(DCL),也听到过两种声音:第一种声音是希望只在第一次创建实例时进行同步,于是才有两次判断instance是否为null的判断;另一种声音是双重锁定检查用在这里根本起不到预想的作用。今天终于知道后一种说法的原因了。
public class SingletonPattern { private static SingletonPattern instance = null; private SingletonPattern(){ } public static SingletonPattern getInstance(){ if(instance == null){ synchronized(SingletonPattern.class){ if(instance == null){ instance = new SingletonPattern(); } } } return instance; } }
看上去貌似是只有在对象还不存在时即第一次创建对象时才会走到synchronized(SingletonPattern.class),instance已经存在了的话,在第一个if(instance == null)时就不满足所以不会进入synchronized(SingletonPattern.class)。真的是这样吗?
首先来看这句instance = new SingletonPattern();这条语句被编译后形成了多条汇编指令,主要做如下三个动作:
1.给SingletonPattern的实例分配内存。
2.初始化SingletonPattern的构造器。
3.将instance对象只想分配的内存空间。
这些汇编指令在JVM中执行,由于Java编译器允许处理器乱序执行,所以上面的动作2和3的顺序是无法保证的,有可能是123也可能是132。如果是132的情况,如果第一个线程在3执行完2未执行前,就被切换到第二个线程上,这时instance因为已经在线程一中执行了动作3,instance已经是费空了,所以线程二直接用这个instance,而这个instance实际上还没有被构造完成,就会出错了。
如果一定要用双重锁定检查来实现单例模式,那在JDK 1.5及之后版本中,可以将instance的声明改成private volatile static SingletonPattern instance = null;就是加了个volatile,这就保证每次用instance都是从主内存中读取,这样就可以使用双重锁定检查来完成单例模式了。当然volatile或多或少也会影响到性能。所以索性不如用下面这种实现了:
public class SingletonPattern2 { private static final SingletonPattern2 singletonPattern = new SingletonPattern2(); private SingletonPattern2(){ } public synchronized static SingletonPattern2 getInstance(){ return singletonPattern; } }
相关文章推荐
- C++11 修复了DCL双重检查锁定问题
- 双重检查锁定及单例模式
- 双重检查锁定及单例模式
- C++和双重检查锁定模式(DCLP)的风险
- 单例模式中的 双重检查锁定(Double-Check Locking ) (多线程下单例模式中的双重检查锁定的实现)
- 单例模式中的 双重检查锁定
- 双重检查锁定及单例模式
- C++11 修复了双重检查锁定问题
- C++和双重检查锁定模式(DCLP)的风险(转)
- 单例模式中的 双重检查锁定(Double-Check Locking ) (多线程下单例模式中的双重检查锁定的实现)
- Singleton - 单例模式和Double-Checked Locking - 双重检查锁定模式
- 双重检查锁定模式(DCL)
- 双重检查锁定及单例模式
- 双重检查锁定在JAVA单例中应用的杯具!
- C++和双重检查锁定模式(DCLP)的风险
- Java盲点:双重检查锁定及单例模式
- 关于双重检查锁定单例模式
- 双重检查锁定及单例模式
- 双重检查锁定模式
- C++双重检查锁定模式(DCLP)的风险