1. 程式人生 > >多執行緒:happens-before原則

多執行緒:happens-before原則

下面就來具體介紹下happens-before原則(先行發生原則):

·        程式次序規則:一個執行緒內,按照程式碼順序,書寫在前面的操作先行發生於書寫在後面的操作

·        鎖定規則一個unlock操作先行發生於後面對同一個鎖的lock操作。(先解鎖,才可以在後面繼續上鎖)

·        volatile變數規則:對一個變數的寫操作先行發生於後面對這個變數的讀操作

·        傳遞規則:如果操作A先行發生於操作B,而操作B又先行發生於操作C,則可以得出操作A先行發生於操作C

·        執行緒啟動規則:Thread物件的start()方法先行發生於此執行緒的每個一個動作

·        執行緒中斷規則:對執行緒interrupt()方法的呼叫先行發生於被中斷執行緒的程式碼檢測到中斷事件的發生

·        執行緒終結規則:執行緒中所有的操作都先行發生於執行緒的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的返回值手段檢測到執行緒已經終止執行(所有終結的執行緒都不可再用)

·        物件終結規則:一個物件的初始化完成先行發生於他的finalize()方法的開始

這8條原則摘自《深入理解Java虛擬機器》。

  這8條規則中,前4條規則是比較重要的,後4條規則都是顯而易見的。


 

  下面我們來解釋一下前4條規則:

  對於程式次序規則來說,我的理解就是一段程式程式碼的執行在單個執行緒中看起來是有序的。注意,雖然這條規則中提到“書寫在前面的操作先行發生於書寫在後面的操作”,這個應該是程式看起來執行的順序是按照程式碼順序執行的,因為虛擬機器可能會對程式程式碼進行指令重排序。雖然進行重排序,但是最終執行的結果是與程式順序執行的結果一致的,它只會對不存在資料依賴性的指令進行重排序。因此,在單個執行緒中,程式執行看起來是有序執行的,這一點要注意理解。事實上,這個規則是用來保證程式在單執行緒中執行結果的正確性,但無法保證程式在多執行緒中執行的正確性

  第二條規則也比較容易理解,也就是說無論在單執行緒中還是多執行緒中,同一個鎖如果出於被鎖定的狀態,那麼必須先對鎖進行了釋放操作,後面才能繼續進行lock操作

  第三條規則是一條比較重要的規則,也是後文將要重點講述的內容。直觀地解釋就是,如果一個執行緒先去寫一個變數,然後一個執行緒去進行讀取,那麼寫入操作肯定會先行發生於讀操作。

  第四條規則實際上就是體現happens-before原則具備傳遞性


一個操作,時間上先發生不代表這個操作就一定是先行發生。反過頭來也一樣。一個操作先行發生也不一定這個操作就是死時間上的先發生!!!

時間先後順序和先行發生原則之間沒有基本沒有太大的關係!所以我們在衡量併發安全問題的時候不要受到時間順序的干擾,一切順序必須先以先行發生原則進行!