JMM和Happen Before

 

線程是操作系統的最小調度單位,也是執行單位,爲了追求高性能,線程裏面的指令執行順序是不定的,這來自編譯器會重排序指令,處理器會亂序或者並行的執行,編譯器還有可能將數據放在處理器的寄存器中等,這些優化技術在單線程的程序中表現得很好,但是到了多線程程序中就有問題了。

 

首先要了解下Java的內存結構,然後我們再進入線程和內存的關係, Java的內存結構如下


 

如果多線程之間不共享數據,這也表現得很好,但是如果多線程之間要共享數據,那麼這些亂序執行,數據在寄存器中這些行爲將導致程序行爲的不確定性,現在處理器已經是多核時代了,這些問題將會更加嚴重,每個線程都有自己的工作內存,多個線程共享主內存,如圖


 

如果共享數據,什麼時候同步到主內存讓別人的線程讀取數據呢?這又是不確定的,如果非要一致,那麼代價高昂,這將犧牲處理器的性能,所以現在的處理器會犧牲存儲一致性來換取性能,如果程序要確保共享數據的時候獲得一致性,處理器通常了提供了一些關卡指令,這個可以幫助程序員來實現,但是各種處理器都不一樣,如果要使程序能夠跨平臺是不可能的,怎麼辦?

 

使用Java,JMM來屏蔽,我們只要和JMM的規定來使用一致性保證就搞定了,那麼JMM又提供了什麼保證呢?JMM的定義是通過動作的形式來描述的,所謂動作,包括變量的讀和寫,監視器加鎖和釋放鎖,線程的啓動和拼接,這就是傳說中的happen before,要想A動作看到B動作的結果,BA必須滿足happen before關係,happen before法則如下:

 

 

1, 程序次序法則,如果A一定在B之前發生,則happen before,

2, 監視器法則,對一個監視器的解鎖一定發生在後續對同一監視器加鎖之前

3, Volatie變量法則:寫volatile變量一定發生在後續對它的讀之前

4, 線程啓動法則:Thread.start一定發生在線程中的動作

5, 線程終結法則:線程中的任何動作一定發生在括號中的動作之前(其他線程檢測到這個線程已經終止,從Thread.join調用成功返回,Thread.isAlive()返回false)

6, 中斷法則:一個線程調用另一個線程的interrupt一定發生在另一線程發現中斷。

7, 終結法則:一個對象的構造函數結束一定發生在對象的finalizer之前

8, 傳遞性:A發生在B之前,B發生在C之前,A一定發生在C之前。

 

發佈了26 篇原創文章 · 獲贊 1 · 訪問量 1227
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章