在代码种加入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 }

 

posted on 2021-11-17 07:33  Sempron2800+  阅读(191)  评论(0编辑  收藏  举报