volatile的硬件语义
:::info 当使用volatile修饰变量时,应用就不会从寄存器中获取该变量的值,而是从内存(高速缓存)中获取。
- JMM规定JVM在遇到volatile关键字的时候要实现一个storeload级别的内存屏障。
- 在实现上Hotspot中遇到 volatile 会调用一个storeload方法,这个方法会去调用一个叫lock的汇编指令,这个指令会锁住总线,保证了指令不重排以及对共享变量的操作是线程独占的。
:::
1. 仅保证单个变量的原子性
对任意**单个**volatile变量的读/写具有原子性,但类似于a++这种复合操作不具有原子性。
如果要实现volatile复合操作的原子性,那么在等号右侧的赋值变量中就不能出现被多线程所共享的变量,哪怕这个变量也是个volatile也不可以。
volatile不能保证以下这些操作的原子性。
volatile int a = b + 2;volatile int a = a++;volatile Date date = new Date();
可以把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步。
可以看成
2. 防止指令重排序(内存屏障)
- 对 volatile 变量的写指令后会加入写屏障
- 对 volatile 变量的读指令前会加入读屏障
- 写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
- 读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前
3. 实现变量的可见性(内存屏障)
对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。
Volatile源码
