图灵学院Java架构师-VIP-指令重排序

指令的基本概念
    指令是指示计算机执行某种操作的命令,如:数据传送指令、算术运算指令、位运算指令、程序流程控制指令、串操作指令、处理器控制指令。指令不同于我们所写的代码,一行代码按照操作的逻辑可以分成多条指令。
     举个例子:int a = 1;  这段代码大致可以分为两条指令:1.加载常量1;2.将常量1赋值给变量a。
 
指令重排序
    Java语言规范JVM线程内部维持顺序花语义,即只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码逻辑顺序不一致,这个过程就叫做指令的重排序。
    指令重排序的意义:使指令更加符合CPU的执行特性,最大限度的发挥机器的性能,提高程序的执行效率。
 
源代码到最终执行的指令序列示意图
指令重排序主要分为三种:
1.编译器重排序:JVM中进行完成的
2.指令级并行重排序
3.处理器重排序:CPU中进行完成的
 
As-If-Serial语义
    as-if-serial语义的意思是:不管怎么进行指令重排序,单线程内程序的执行结果不能被改变。编译器,处理器进行指令重排序都必须要遵守as-if-serial语义规则。
    为了遵守as-if-serial语义,编译器和处理器对存在依赖关系的操作,都不会对其进行重排序,因为这样的重排序很可能会改变执行的结果,但是对不存在依赖关系的操作,就有可能进行重排序。
 
Happens-Before原则
    happens-before可以理解为“先于”,是用来指定两个操作之间的执行顺序,由于这个两个操作可以在一个线程之内,也可以在不同线程之间。因此,JMM可以通过happens-before关系来保证跨线程的内存可见性(如果A线程是对变量进行写操作,而B线程是对变量进行读操作,那么如果A线程是先于B线程的操作,那么A线程写操作之后的数据对B线程也是可见的)
具体的定义:
    1.如果一个操作“先于”另一个操作,那么第一操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前;
    2.两个操作是happens-before的关系,也并不意味着JVM会按照这个关系去顺序执行,因为会存在重排序的可能,但是进行了重排序的执行结果,与此happens-before的关系顺序执行的结果一致的话,那就说明这个重排序是合法的(也就是JVM允许这样的重排序)。
 
具体规则:
    1.程序顺序规则:在一个线程内必须保证语义串行性,也就是按照代码顺序执行;
    2.监视器(管程)锁规则:无论是单线程还是对线程环境,对于同一个锁来说,解锁操作必须是先于后一个加锁操作之前(如果A线程进行了加锁,还未进行解锁,那么B线程是不可能进行加锁操作的,只有等到A线程进行解锁操作之后,才能再进行加锁操作),而且前者线程解锁之后,对数据的操作对于后者加锁的线程是可见的;
    3.volatile规则:volatile变量的写先于变量的读,保证了volatile变量的可见性,简而言之,volatile变量每次别线程访问时,都强迫从主内存中读该变量的值,而当变量的值被修改时,又会强迫将最新的值从工作内存刷回主内存中,任何时刻,不同线程总是能获取到该变量的最新值;
    4.线程启动规则:线程的start方法先于此线程run方法中的所有操作(线程一定是执行start方法之后,才会执行真正的run方法逻辑),如果A线程在执行过程中,执行B线程的start方法,那么在A线程执行过程中到B线程start这一段区域中对共享变量的修改,对线程B是可见的;
    5.线程终止规则:线程run方法中的执行操作一定是先于此线程的join方法的,如果B线程修改了共享变量的值,那么在B线程执行join方法之后,主线程一定对此共享变量是可见的;
    6.线程中断规则:对线程 interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测线程是否中断;
    7.传递性:A先于B,B先于C,那么一定可以知道A先于C;
    8.对象终结规则:一个对象的初始化完成(构造函数执行完成)一定先于finalize方法(对象被回收时会调用,即垃圾回收时)之前执行,也就是现有对象才能进行对象回收操作。
 
 
As-if-Serial 和 Happens-Before原则
1. as-if-serial语义保证单线程内程序的执行结果不被改变,happens-before关系保证正确同步的多线程程序的执行结果不被改变;
2.as-if-serial语义给编写单线程程序的程序员创造了一个幻境:单线程程序是按程序的顺序来执行的。happens-before关系给编写正确同步的多线程程序的程序员创造了一个幻境:正确同步的多线程程序是按happens-before指定的顺序来执行的;
3.as-if-serial语义和happens-before这么做的目的,都是为了在不改变程序执行结果的前提下,尽可能地提高程序执行的并行度。
 
符合Happens-before规则的多线程程序才是正确的逻辑,符合As-if-serial语义的单线程程序才是正确的逻辑,这也是保证了程序员对代码编写的逻辑合理性。
 
 
 
 
 

猜你喜欢

转载自www.cnblogs.com/jackeason/p/11336306.html