指令重排序


指令的基本概念
    指令是指示計算機執行某種操作的命令,如:數據傳送指令、算術運算指令、位運算指令、程序流程控制指令、串操作指令、處理器控制指令。指令不同於我們所寫的代碼,一行代碼按照操作的邏輯可以分成多條指令。
     舉個例子: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語義的單線程程序才是正確的邏輯,這也是保證了程序員對代碼編寫的邏輯合理性。
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM