volatile 的底层实现原理是内存屏障,Memory Barrier(Memory Fence)
- 对 volatile 变量的写指令后会加入写屏障
- 对 volatile 变量的读指令前会加入读屏障
保证可见性
-
写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中
public void actor2(I_Result r) { num = 2; ready = true; // ready是被volatile修饰的 ,赋值带写屏障 // 写屏障 }
-
而读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据
public void actor1(I_Result r) { // 读屏障 // ready是被volatile修饰的 ,读取值带读屏障 if(ready) { r.r1 = num + num; } else { r.r1 = 1; } }
保证有序性
-
写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
public void actor2(I_Result r) { num = 2; ready = true; // ready是被volatile修饰的 , 赋值带写屏障 // 写屏障 }
-
读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前
public void actor1(I_Result r) { // 读屏障 // ready是被volatile修饰的 ,读取值带读屏障 if(ready) { r.r1 = num + num; } else { r.r1 = 1; } }
不保证原子性
虽然读写凭照保证了可见性和有序性,但是不能保证其他线程的读跑到本线程的写之前。所以无法保证原子性。
比如static int i
在多线程下的i++和i–操作。