Java Happens-before法則

Java存儲模型有一個happens-before原則,就是如果動作B要看到動作A的執行結果(無論A/B是否在同一個線程裏面執行),那麼A/B就需要滿足happens-before關係。

在介紹happens-before法則之前介紹一個概念:JMM動作(Java Memeory Model Action),Java存儲模型動作。一個動作(Action)包括:變量的讀寫、監視器加鎖和釋放鎖、線程的start()和join()。後面還會提到鎖的的。

happens-before完整規則:

(1)同一個線程中的每個Action都happens-before於出現在其後的任何一個Action。

(2)對一個監視器的解鎖happens-before於每一個後續對同一個監視器的加鎖。

(3)對volatile字段的寫入操作happens-before於每一個後續的同一個字段的讀操作。

(4)Thread.start()的調用會happens-before於啓動線程裏面的動作。

(5)Thread中的所有動作都happens-before於其他線程檢查到此線程結束或者Thread.join()中返回或者Thread.isAlive()==false。

(6)一個線程A調用另一個另一個線程B的interrupt()都happens-before於線程A發現B被A中斷(B拋出異常或者A檢測到B的isInterrupted()或者interrupted())。

(7)一個對象構造函數的結束happens-before與該對象的finalizer的開始

(8)如果A動作happens-before於B動作,而B動作happens-before與C動作,那麼A動作happens-before於C動作。

volatile語義

到目前爲止,我們多次提到volatile,但是卻仍然沒有理解volatile的語義。

volatile相當於synchronized的弱實現,也就是說volatile實現了類似synchronized的語義,卻又沒有鎖機制。它確保對volatile字段的更新以可預見的方式告知其他的線程。

volatile包含以下語義:

(1)Java 存儲模型不會對valatile指令的操作進行重排序:這個保證對volatile變量的操作時按照指令的出現順序執行的。

(2)volatile變量不會被緩存在寄存器中(只有擁有線程可見)或者其他對CPU不可見的地方,每次總是從主存中讀取volatile變量的結果。也就是說對於volatile變量的修改,其它線程總是可見的,並且不是使用自己線程棧內部的變量。也就是在happens-before法則中,對一個valatile變量的寫操作後,其後的任何讀操作理解可見此寫操作的結果。

儘管volatile變量的特性不錯,但是volatile並不能保證線程安全的,也就是說volatile字段的操作不是原子性的,volatile變量只能保證可見性(一個線程修改後其它線程能夠理解看到此變化後的結果),要想保證原子性,目前爲止只能加鎖!

volatile通常在下面的場景:

 

volatile boolean done = false;
    
while! done ){
        dosomething();
    }

 

應用volatile變量的三個原則:

(1)寫入變量不依賴此變量的值,或者只有一個線程修改此變量

(2)變量的狀態不需要與其它變量共同參與不變約束

(3)訪問變量不需要加鎖

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