volatile关键字对原子性、可见性以及有序性的保证
volatile对原子性的保证真的是非常的有限,其实主要就是32位jvm中的long/double类型变量的赋值操作是不具备原子性的,加上volatile就可以保证原子性了。
eg:
volatile boolean isRunning = true;
线程1:
Release屏障
isRunning = false;
Store屏障 => 原理,没有过多的牵扯到内存屏障的一些东西,可见性和有序性,主要都是基于各种内存屏障来实现的。
线程2:
Load屏障
while(isRunning) {
Acquire屏障
// 代码逻辑
}
在volatile变量写操作的前面会加入一个Release屏障,然后在之后会加入一个Store屏障,这样就可以保证volatile写跟Release屏障之前的任何读写操作都不会指令重排,然后Store屏障保证了,写完数据之后,立马会执行flush处理器缓存的操作。
在volatile变量读操作的前面会加入一个Load屏障,这样就可以保证对这个变量的读取时,如果被别的处理器修改过了,必须得从其他处理器的高速缓存(或者主内存)中加载到自己本地高速缓存里,保证读到的是最新数据。
在之后会加入一个Acquire屏障,禁止volatile读操作之后的任何读写操作会跟volatile读指令重排序。
Acquire屏障其实就是LoadLoad屏障 + LoadStore屏障,Release屏障其实就是StoreLoad屏障 + StoreStore屏障。
volatile读写前后会加屏障,避免跟前后的读写操作发生指令重排。
volatile和synchronized保证可见性和有序性,原来都是通过各种内存屏障来实现的,因为加了内存屏障,就会有一些特殊的指令和实现,就可以保证可见性和有序性了,有序性在几个阶段的指令重排的问题。