Volatile是否有原子性保证带来的思考

      最近跟同事讨论Volatile原子性的问题,他突然问我为什么Volatile不能保证原子性,因为上一个面试官问过他这个问题,听见这个问题其实我特别的奇怪,因为Volatile跟原子性保障有什么关系吗?

      在讲原子性之前,我们首先得知道Volatile关键字的具体含义,根据JMM内存模型的规定,java内存模型针对线程而言采用缓存与主存的方式对变量进行操作。

     也就是说在线程运行的时候,如果需要对外部变量进行引用,我们首先从主内存获取变量的值(可以理解为java堆),然后将获取的值放入线程的工作内存,这里可以理解为放入了栈帧里面,栈帧保存了线程的局部变量表,包括(int long byte等类型)。之后再通过对线程内的工作内存的变量进行操作。正常进行到这一步都没有什么问题,但是我们都知道线程外的变量位于java堆,而java堆是线程共享的,也就是说这些个变量都会被外部的其他线程所引用,如果此时外部的其他线程对这个共享变量进行了操作,那就势必会改变变量的值,到这里,Volatile的可见性就显示了出来,Volatile修饰的变量对于其他线程来说都是可见的,因为Volatile修饰的变量会让线程依旧按照JMM模型规范去将变量放入线程工作内存,当变量发生改变的时候,会通知线程告知线程内存的变量值失效,需要重新获取主内存的变量值,而没有用Volatile修饰的变量则不会进行这一步,到这里我们就知道了Volatile的用途,就是让所有线程第一时间知道主内存的变量值的更改信息,并随时进行更新。

     当然再深入一点,读者们可以详细的去了解一下内存屏障,重排序和happens-before原则,Volatile的另一个作用也是阻止了重排序,而重排序的概念可能会颠覆读者对JAVA语言之前的认知,有兴趣的可以了解一下。

     那么Volatile有原子性保证吗?答案是没有的,因为当你读取数据的那一刻,放入线程内存的那一刻,原子操作就已经开始了。(当然如果你认为这不是原子操作,那你可以说Volatile有原子性保证。)

    所以总结下来,我认为在高并发情景下所要使用的变量最好都使用Volatile关键字来修饰,除非你有特殊的业务要求,因为Volatile只是保证高并发情况下的其中一个条件,另外个条件就是需要进行上锁,或者使用一些高并发的常用数据结构,例如ConcurrentHashMap。

    那既然有了Synchronized这个锁,为什么我们还需要Volatile这个关键字呢,我直接锁住对象不就可以了吗?因为Synchronized在jdk1.6之前是重量级锁,在1.6之后变成了适应性量级锁(我是这么称呼它的),1.6之后的Synchronized会根据线程的竞争是否激烈来逐渐进行演变,其中包括适应性自旋,锁消除,锁粗化,轻量级锁,偏向锁。

   以上是从Volatile关键字引申出来的思考,如果有错误之处,还希望读者不吝指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值