volatile的作用
volatile是轻量级的synchronized。java线程访问共享变量时,可以确保共享变量能被准确和一致地更新。
volatile保证内存的可见性
我们知道现代硬件内存架构中,CPU与内存之间往往存在着缓存以提高处理速度,CPU在进行操作时,是对缓存中的数据进行操作,而不会对内存的数据直接进行操作。
volatile修饰的共享变量在进行写操作的时候会多出一条Lock前缀的汇编代码。这条指令有以下两种作用
- 将缓存中更新完毕的变量数据写回到系统内存。
- 这个写回内存的操作使得其他处理器对该数据的缓存无效。(通过嗅探)处理器从而读取内存中的最新数据,达到数据的一致性。
volatile保证顺序性,禁止指令重排序
JMM通过对每个volatile变量的前后插入适当的内存屏障,以保障普通变量的操作不会与volatile变量进行重排序。
重排序
重排序是指编译器和处理器为了优化程序而对指令序列进行重新排序的一种手段。根据数据依赖性,只要保证重排序后的执行结果与排序前的执行结果一致,JMM是允许这种排序的,从而提高并行度。
volatile的内存语义
volatile写的内存语义
当写一个volatile变量时,JMM将线程对应的本地内存中的共享变量强制刷回主内存。
volatile读的内存语义
当读一个volatile变量时,JMM会把线程对应的本地内存置为无效,从主内存读取共享变量。
happens-before
一个volatile变量的写先于后续对这个volatile变量的读。即写操作必发生在读操作之前。
public class VolatileExample {
private int a = 0;
private volatile boolean flag = false;
public void writer(){
a = 1; //1
flag = true; //2
}
public void reader(){
if(flag){ //3
int i = a; //4
}
}
}// 2 先于 3,1先于2,3先于4 => 1先于4