双检锁(DCL)下volatile的作用

先放代码:

public class Singleton
{
	private static volatile Singleton instance;
	private Singleton() {}
	public static Singleton getInstance()
	{
		if(instance==null)
		{
			synchronized(Singleton.class)
			{
				if(instance==null)
				{
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
}

然后来分析getInstance()每一步的作用

第一个if语句,用来确认调用getInstance()时instance是否为空,如果不为空即已经创建,则直接返回,如果为空,那么就需要创建实例,于是进入synchronized同步块。

synchronized加类锁,确保同时只有一个线程能进入,进入以后进行第二次判断,是因为,

对于首个拿锁者,它的时段instance肯定为null,那么进入new Singleton()对象创建,

而在首个拿锁者的创建对象期间,可能有其他线程同步调用getInstance(),那么它们也会通过if进入到同步块试图拿锁然后阻塞。

这样的话,当首个拿锁者完成了对象创建,之后的线程都不会通过第一个if了,而这期间阻塞的线程开始唤醒,它们则需要靠第二个if语句来避免再次创建对象。

以上就是双检索的实现思路,synchronized与第二个if即是用来保证线程安全与不产生第二个实例,也是Double_Checked_Lock由来。

那么volatile的作用体现在哪呢?

一开始我认为是volatile的同步性,因为要在首个拿锁者创建对象以后,立即保证instance的可见性,以让被唤醒的阻塞线程能够在第二个if语句的时候得到instance非空的结果。

但这个可见性其实是用synchronized来保障的,并不需要volatile来多此一举了。

后来才知道应该是避免指令重排序,说明如下

这里的指令重排序主要体现在instance = new Singleton()这条语句上了。

这条语句显然是个复合操作,可以简单分下,(已完成类加载 ,假设在堆上分配内存)

1.在堆中分配对象内存

2.填充对象必要信息+具体数据初始化+末位填充

3.将引用指向这个对象的堆内地址

那么,在完成1后,对象的大小和地址已经确定,因此,2和3其实存在指令重排序的可能。

并且可以看到,3的操作明显比2要少,那么如果让2与3一起执行,并且反应到具体的顺序上变成了1-3-2.

先完成3,引用变量instance先指向了在堆中给对象分配的空间,然后2仍在慢慢吞吞继续。

这时候,被synchronized挡在外面的阻塞线程其实是不会有什么影响的,因为一定会等到对象创建完,首个拿锁者才会释放锁。

那么关键是在,此刻如果在3完成而2未完成这个临界点,有一个新线程调用getInstance(),那么第一个if,会怎么样?

答案是因为第一个if没在同步块里,而此时instance已经非空,指向具体内存地址了,所以直接返回此时未完成初始化的instance实例

那么如果在Singleton里有个变量int number ,有个方法int getNumber()返回number,这时候调用

Singleton.getInstance().getNumber();

会怎样?

不知道,可能会报错,或者会得到错误结果,但这就是我能想到的volatile避免的情况了。

volatile修饰变量避免指令重排序,保证1-2-3按顺序来,这样即使在首个拿锁者未释放锁前,有线程切入,当它在第一个if处得到instance非空时,此时instance的初始化也一定已经完成。

因此这就是volatile在DCL的作用了。

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值