背景:
处理器在执行内存写操作时,先将数据写入缓冲期中,而不是直接写入高速缓存。所以在多核处理器时代,会产生变量可见性的问题。而编译器和执行期为提高性能会对指令进行重排序,在多线程环境下可能会造成结果不符合预期,而volatile提供了内存可见性已经禁止重排的特性。
保证内存可见性
现象:
被volatile修饰的关键字,当发生修改后立即刷新到主内存,当其他cpu需要读取这个volatile变量时设置本地缓存中该变量地址无效,从主内存重新读取,实现了内存可见性
原理:
编译器在编译时发现volatile,插入lock(即内存屏障)前缀指令,而lock有以下2个特性
1.写变量后会强制刷新回主内存
2.读该变量时会直接从主内存读取
禁止指令重排序
现象:JMM(java内存模型)基于happens-before原则基于volatile的写happens-before对volatile变量的读,实现执行顺序
原理:编译器发现一个volatile变量,那么在编译的时候会加入内存屏障(也就是指令),当cpu对这个变量做操作前后强制向主内存读写,而不经过cpu自己的本地缓存区
无法保证原子性&安全性
volatile无法保证原子性,因为对于一个变量的读操作,可以解释为以下3部分
- 读取volatile变量到本地
- 修改变量值
- local值写会主内存
所以在这3步中无法保证原子性,juc包中提供了automic*组件保证原子操作