二十二、应用双重锁定检查于单例模式中的问题

之前在很多单例类中看到双重锁定检查(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;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值