標籤:
主記憶體與工作記憶體定義程式中各個變數的訪問規則。規定JVM必須遵循的最小保證。定義操作的偏序關係。Happens-Before規則:發布共用對象與另一線程訪問對象。 說明了某個線程的記憶體操作,在哪些情況下對其他線程是可見的。 之前發生:Happens-Before 一代碼塊在其他開始前完成。同步約束:Synchronized-with 把物件檢視與主記憶體同步 【規則】1.解鎖與後續鎖操作存在同步約束。2.volatile變數寫入和讀取存在同步約束。3.若A受到B的同步約束,則A在B之前發生。4.程式中A出現在B之前,則A在B之前發生。 Java語言的記憶體模型由一些規則組成,這些規則確定線程對記憶體的訪問如何排序以及何時可以確保它們對線程是可見的。 【特徵】原子性,可見度,有序性。【編譯器操作指令的重排序】
記憶體模型描述了程式的可能行為。具體的編譯器實現可以產生任意它喜歡的代碼 -- 只要所有執行這些代碼產生的結果,能夠和記憶體模型預測的結果保持一致。這為編譯器實現者提供了很大的自由,包括操作的重排序。
編譯器產生指令的次序,可以不同於原始碼所暗示的“顯然”版本。
重排序後的指令,對於最佳化執行以及成熟的全域寄存器分配演算法的使用,都是大有脾益的,它使得程式在計算效能上有了很大的提升。
重排序類型包括:
- 編譯器產生指令的次序,可以不同於原始碼所暗示的“顯然”版本。
- 處理器可以亂序或者並行的執行指令。
- 緩衝會改變寫入提交到主記憶體的變數的次序。
記憶體可見度
由於現代可共用記憶體的多處理器架構可能導致一個線程無法馬上(甚至永遠)看到另一個線程操作產生的結果。所以 Java 記憶體模型規定了 JVM 的一種最小保證:什麼時候寫入一個變數對其他線程可見。
在現代可共用記憶體的多處理器體繫結構中每個處理器都有自己的緩衝,並周期性的與主記憶體協調一致。假設線程 A 寫入一個變數值 V,隨後另一個線程 B 讀取變數 V 的值,在下列情況下,線程 B 讀取的值可能不是線程 A 寫入的最新值:
- 執行線程 A 的處理器把變數 V 緩衝到寄存器中。
- 執行線程 A 的處理器把變數 V 緩衝到自己的緩衝中,但還沒有同步重新整理到主記憶體中去。
- 執行線程 B 的處理器的緩衝中有變數 V 的舊值。
Happens-before 關係
happens-before 關係保證:如果線程 A 與線程 B 滿足 happens-before 關係,則線程 A 執行動作的結果對於線程 B 是可見的。如果兩個操作未按 happens-before 排序,JVM 將可以對他們任意重排序。
下面介紹幾個與理解 ConcurrentHashMap 有關的 happens-before 關係法則:
- 程式次序法則:如果在程式中,所有動作 A 出現在動作 B 之前,則線程中的每動作 A 都 happens-before 於該線程中的每一個動作 B。
- 監視器鎖法則:對一個監視器的解鎖 happens-before 於每個後續對同一監視器的加鎖。
- Volatile 變數法則:對 Volatile 域的寫入操作 happens-before 於每個後續對同一 Volatile 的讀操作。
- 傳遞性:如果 A happens-before 於 B,且 B happens-before C,則 A happens-before C。
Java記憶體模型