程序笔记   发布时间:2022-07-19  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了volatile 指令重排的理解大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

指令重排

内存可见性只是 volatile 的其中一个语义,它还可以防止 JVM 进行指令重排优化。

举一个伪代码:

  1. int a=10 ;//1
  2. int b=20 ;//2
  3. int c= a+b ;//3

一段特别简单的代码,理想情况下它的执行顺序是: 1>2>3。但有可能经过 JVM 优化之后的执行顺序变为了 2>1>3

可以发现不管 JVM 怎么优化,前提都是保证单线程中最终结果不变的情况下进行的。

可能这里还看不出有什么问题,那看下一段伪代码:

private static Map<String,String> value ;
private static volatile Boolean flag = fasle ;
//以下方法发生在线程 A 中 初始化 Map
public void initMap(){
   //耗时操作
   value = getMapValue() ;//1
   flag = true ;//2
}
//发生在线程 B中 等到 Map 初始化成功进行其他操作
public void doSomeThing(){
   while(!flag){
       sleep() ;
   }
   //dosomething
   doSomeThing(value);
}

这里就能看出问题了,当 flag 没有被 volatile 修饰时, JVM 对 1 和 2 进行重排,导致 value 都还没有被初始化就有可能被线程 B 使用了。

所以加上 volatile 之后可以防止这样的重排优化,保证业务的正确性。

指令重排的的应用

一个经典的使用场景就是双重懒加载的单例模式了:

public class Singleton {
   private static volatile Singleton singleton;
   private Singleton() {
   }
   public static Singleton geTinstance() {
       if (singleton == null) {
           synchronized (Singleton.class) {
               if (singleton == null) {
                   //防止指令重排
                   singleton = new Singleton();
               }
           }
       }
       return singleton;
   }
}

这里的 volatile 关键字主要是为了防止指令重排。

如果不用 , singleton=newSingleton();,这段代码其实是分为三步:

  • 分配内存空间。(1)
  • 初始化对象。(2)
  • singleton 对象指向分配的内存地址。(3)

加上 volatile 是为了让以上的三步操作顺序执行,反之有可能第二步在第三步之前被执行就有可能某个线程拿到的单例对象是还没有初始化的,以致于报错。

大佬总结

以上是大佬教程为你收集整理的volatile 指令重排的理解全部内容,希望文章能够帮你解决volatile 指令重排的理解所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。