在代码种加入volatile关键字时,生成的汇编代码会出现一个locl前缀指令。
local前缀指令实际上相当于一个内存屏障,它有3个功能:
1.它确保指令重排序时不会把后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面。即在执行到内存屏障位置时,它前面的操作已全部完成。
2.它会强制将对缓存的修改操作立即写入主存。
3.如果是写操作,它会导致其他CPU中对应的缓存行无效。
所以可见性和禁止指令重排序如下:
可见性:
volatile的功能就是被修饰的变量的值修改后,可以立即同步到主内存,被修饰的变量在每次用之前都从主内存刷新。本质也是通过内存屏障来实现可见性。
写内存屏障可以促使处理器将当前store buffer(存储缓存)的值写回主存。
读内存屏障可以促使处理invalidate queue(失效队列)。从而避免存储缓存和失效队列的非实时性带来的问题。
禁止指令重排:
volatile是通过内存屏障来禁止指令重排,JMM内存屏障策略:storestore、storeload、loadload、loadstore
store为写操作,load为读操作。
典型使用场景为单例模式的双重检查机制,代码如下:
1 public class MultiThreadSingleton { 2 3 private static volatile MultiThreadSingleton multiThreadsSingleton = null; 4 5 private MultiThreadSingleton() { 6 System.out.println("MultiThreadSingleton init"); 7 } 8 9 public static MultiThreadSingleton getInstance() { 10 if (multiThreadsSingleton == null) { 11 synchronized (MultiThreadSingleton.class) { 12 if (multiThreadsSingleton == null) { 13 multiThreadsSingleton = new MultiThreadSingleton(); 14 } 15 } 16 } 17 return multiThreadsSingleton; 18 } 19 20 public static void main(String[] args) { 21 // TODO Auto-generated method stub 22 for (int i = 0; i < 10; i++) { 23 new Thread(() -> { 24 MultiThreadSingleton.getInstance(); 25 }).start(); 26 } 27 28 } 29 }