美文网首页
Java中的指令重排序

Java中的指令重排序

作者: 小毛1221 | 来源:发表于2018-08-11 17:26 被阅读0次

重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境。

编译期重排序的典型就是通过调整指令顺序,在不改变程序语义的前提下,尽可能减少寄存器的读取、存储次数,充分复用寄存器的存储值。

//以下操作在同一个线程中执行
int i = 1;
int j = 2;

int j = 2的代码完全可能先被处理器执行,这并不影响先行先发生原则,因为我们在这条线程中没有办法感知到这点。(都是赋值操作,无论先发生哪一个,最终结果都与顺序执行一样)。但如果有其他线程在读取这两个值,重排序就会造成读取错误!

对于单一线程,如果有办法感知到这点,即int a = 1;int b = a;那么就不能重排序。

如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖。数据依赖分下列三种类型:

名称 代码示例 说明
写后读 a = 1;b = a; 写一个变量之后,再读这个位置。
写后写 a = 1;a = 2; 写一个变量之后,再写这个变量。
读后写 a = b;b = 1; 读一个变量之后,再写这个变量。

上面三种情况,只要重排序两个操作的执行顺序,程序的执行结果将会被改变。所以,编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。也就是说:在单线程环境下,指令执行的最终效果应当与其在顺序执行下的效果一致,否则这种优化便会失去意义。这句话有个专业术语叫做as-if-serial semantics (as-if-serial语义)。

class ReorderExample {  
  int a = 0;  
  boolean flag = false;  

  public void writer() {  
    a = 1;          // 1  
    flag = true;    // 2  
  }  

  public void reader() {  
    if (flag) {            // 3  
      int i = a * a; // 4  
    }  
  }  
}  

flag变量是个标记,用来标识变量a是否已被写入。这里假设有两个线程A和B,A首先执行writer()方法,随后B线程接着执行reader()方法。线程B在执行操作4时,能否看到线程A在操作1对共享变量a的写入?
答案是:不一定能看到。

由于操作1和操作2没有数据依赖关系,编译器和处理器可以对这两个操作重排序;同样,操作3和操作4没有数据依赖关系,编译器和处理器也可以对这两个操作重排序。可以使用synchronized修饰这两个方法,或者将flag设为volatile解决这个问题(由先行先发生原则可知)。

如果A happens- before B,JMM并不要求A一定要在B之前执行。JMM仅仅要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前。
如果操作A的执行结果不需要对操作B可见;而且重排序操作A和操作B后的执行结果,与操作A和操作B按happens- before顺序执行的结果一致。在这种情况下,JMM会认为这种重排序并不非法(not illegal),JMM允许这种重排序。

相关文章

  • Java指令重排序

    Java指令重排序Java内存模型允许编译器和处理器对指令重排序以提高运行性能,并且只会对不存在数据依赖性的指令重...

  • 单例模式注意事项

    单例中的类变量定义加 volatile : 禁止java指令重排序

  • 重排序 VS 可见性 VS 原子性

    重排序 代码实际执行顺序和代码在 Java 文件中的顺序不一致,代码指令并不是严格按照代码语句顺序执行的,这就是重...

  • Java中的指令重排序

    重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。重排序分为两类:编译期重排...

  • 面试:用 Java 逆序打印链表

    面试:用 Java 逆序打印链表 昨天的 Java 实现单例模式 中,我们的双重检验锁机制因为指令重排序问题而引入...

  • FreeMarker | 笔记篇

    java中Freemarker list指令详解 java中Freemarker if else指令详解 java...

  • java volatile

    重排序 在Java内存模型中,为了效率是允许编译器和处理器对指令进行重排序,重排序它不会影响单线程的运行结果,但是...

  • Java指令重排序与volatile关键字

    Java指令重排序与volatile关键字 1. 重现代码重排序 1.1 测试代码 完整代码参见Github,其中...

  • 双重检查锁定(double-checked locking)与单

    可以使用volatile变量禁止指令重排序,让DCL生效: [java]view plaincopy packag...

  • volatile关键词的使用和内幕

    一些知识总结,主要是从深入理解JVM虚拟中摘抄的。 语义 多线程的可见性和禁止指令重排序优化 JAVA中内存模型 ...

网友评论

      本文标题:Java中的指令重排序

      本文链接:https://www.haomeiwen.com/subject/frbdbftx.html