2021-02-24

volatile 关键字

什么是volatile关键字

如何使用volatile关键字

什么是volatile关键字:
Java 的volatile关键字保证了线程之间对变量的可见性,Java volatile关键字最初就是被设计成解决变量可见性问题的。只要将变量声明成volatile,那所有变量的写操作都会立即被写回到主内存中。同理,所有对变量的读操作也会被直接从主内存中读取。
如下使用volatile关键字:

public class  A  {
    public int number = 0;

}

这样,把变量声明为volatile以后,凡是对这个变量的写操作,都具有可见性。
volatile使用原理
volatile可以保证线程可见性且提供了一定的有序性,但是无法保证原子性。在JVM底层volatile是采用“内存屏障”来实现的。观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令,lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
(1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
(2)它会强制将对缓存的修改操作立即写入主存;
(3)如果是写操作,它会导致其他CPU中对应的缓存行无效。

禁止指令重排
重排序是指编译器和处理器为了优化程序性能而对指令序列进行排序的一种手段。重排序需要遵守一定规则:
(1)重排序操作不会对存在数据依赖关系的操作进行重排序。
  比如:a=1;b=a; 这个指令序列,由于第二个操作依赖于第一个操作,所以在编译时和处理器运行时这两个操作不会被重排序。
(2)重排序是为了优化性能,但是不管怎么重排序,单线程下程序的执行结果不能被改变
  比如:a=1;b=2;c=a+b这三个操作,第一步(a=1)和第二步(b=2)由于不存在数据依赖关系, 所以可能会发生重排序,但是c=a+b这个操作是不会被重排序的,因为需要保证最终的结果一定是c=a+b=3。
重排序在单线程下一定能保证结果的正确性,但是在多线程环境下,可能发生重排序,影响结果,下例中的1和2由于不存在数据依赖关系,则有可能会被重排序,先执行status=true再执行a=2。而此时线程B会顺利到达4处,而线程A中a=2这个操作还未被执行,所以b=a+1的结果也有可能依然等于2。

Java volatile保证了Happens-Before
为了解决指令重排序带来的挑战,Java volatile关键字对"happens-before"的情况做出可见性的保证,这种机制如下:

如果代码中对非volatile变量的读、写的指令发生在对volatile变量的写指令之前,这些指令将确保不会被重排序。换言之,只要满足以下条件:非volatile变量的读写操作只要发生在volatile变量的写操作之前,代码都不会被重排序。即保证了对非volatile变量的操作“happen before”对volatile变量的操作。但请注意,如果对非volatile变量的读写操作发生在对volatile变量的写操作之后,还是有可能被重排序到对volatile变量的写操作之前的。总之,从后到前是允许的,但从前到后是不允许的。
因此,强制加上volatile关键字保证的可见性,是通过上述的这种“happens-before‘机制所保证的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值