深入理解Java內(nèi)存模型 ch1基礎(chǔ)

1.并發(fā)編程模型的分類

并發(fā)編程的兩個關(guān)鍵問題:

  • 通信
  • 同步

通信機制有兩種:

  • 共享內(nèi)存
  • 消息傳遞

同步:用于控制不同程序之間操作發(fā)生相對順序的機制。

  • 共享內(nèi)存模式里,必須顯式指定某個方法或某段代碼需要在線程間互斥執(zhí)行。
  • 消息傳遞的并發(fā)模型里,由于消息的發(fā)送必須在消息接收之前,因此同步是隱式進行的。

Java并發(fā)采用的是共享內(nèi)存模型。

2.Java內(nèi)存模型的抽象

JMM決定一個線程對共享變量的寫入何時對另一個線程可見。

抽象來看,JMM定義了線程和主內(nèi)存之間的抽象關(guān)系:線程之間的共享變量存儲在主內(nèi)存中,每個線程都有一個私有的本地內(nèi)存。本地內(nèi)存指緩存、寄存器以及其他硬件和編譯器的優(yōu)化。



如下兩個步驟實質(zhì)上是線程A向線程B發(fā)送消息,而且這個通信過程必須要經(jīng)過主內(nèi)存。JMM通過控制主內(nèi)存與每個線程的本地內(nèi)存之間的交互,來為Java程序員提供內(nèi)存可見性保證。


3.重排序

三種類型的重排序:

  • 編譯器優(yōu)化重排序。前提:不改變單線程程序語義。
  • 指令級并行的重排序。前提:不存在數(shù)據(jù)依賴性。
  • 內(nèi)存系統(tǒng)的重排序。由于使用了緩沖區(qū),使得加載、存儲看上去可能是亂序執(zhí)行的。



    1屬于編譯器重排序,2、3屬于處理器重排序。

對于編譯器,JMM的編譯器重排序規(guī)則會禁止特定類型的編譯器重排序。
對于處理器重排序,JMM的處理器重排序規(guī)則會要求java編譯器生成指令序列時,插入特定類型的內(nèi)存屏障指令,通過內(nèi)存屏障指令來禁止特定類型的處理器重排序。

4.處理器重排序與內(nèi)存屏障指令

4.1 處理器重排序

寫緩存的優(yōu)點:

  • 寫緩沖區(qū)可以保證指令 流水線持續(xù)運行,它可以避免 由于處理器停頓下來等待向內(nèi)存寫入數(shù)據(jù) 而產(chǎn)生的延遲。
  • 通過以 批處理的方式刷新寫緩沖區(qū),以及合并 寫緩沖區(qū)中 對同一內(nèi)存地 址的多次寫,可以減少對內(nèi)存總線占用。

帶來的問題:

  • 雖然緩沖區(qū)有這么好處但 每個處 理器上的寫緩沖區(qū), 僅僅對它所在的處理器可見。這個特性會內(nèi)存操作執(zhí)行順 序產(chǎn)生重要的影響: 處理器對內(nèi)存的讀/寫操作的執(zhí)行 順序 ,不一定與內(nèi)存實際發(fā)生的讀 /寫操作 順序一致!

從內(nèi)存操作實際發(fā)生的順序來看,直到 處理器 A執(zhí)行 A3 來刷新自己的寫緩存區(qū), 寫操作 A1 才算真正執(zhí)行了。
雖然處理器 A執(zhí)行內(nèi)存操作的順序為: A1 ->A2 ,但內(nèi)存操作實際發(fā)生的順序卻是: A2 ->A1 。此時,處理器 A的內(nèi)存操作順序被重排序了。

總結(jié)如下:
由于寫緩沖區(qū)僅對自己處理器可見 ,它會導致處理器執(zhí)行內(nèi)存操作的順序可能會與內(nèi)存實際 的操作執(zhí)行順序不一致 。

常見處理器允許的重排序類型

4.2 內(nèi)存屏障

為了保證內(nèi)存可見性, java編譯器在生成指令序列的適當位置指令序列的適當位置會插入內(nèi)存屏障指令來禁止特定類型的處理器重排序。
JMM把內(nèi)存屏障指令分為四類:



StoreLoad Barriers是一個“全能型”的屏障,它同時具有其他三效果。 現(xiàn)代的多處理器大都支持該屏障(其他類型的屏障不一定被所有處理器支持)。 執(zhí)行該屏障開銷會很昂貴 ,因為當前處理器通常要把寫緩沖區(qū)中的數(shù)據(jù)全部刷新到內(nèi)存中 (buffer fully flush)。

5.happens-before

從 JDK5開始, java使用新的JSR -133內(nèi)存模型。
JSR -133 使用happens-before的概念來闡述操作之間的內(nèi)存可見性。 在 JMM中, 如果一個操作執(zhí)行的結(jié)需要對另可見,那 么這兩個操作之間必須要存在 happens-before關(guān)系 。

注意,兩個操作之間具有happens-before關(guān)系,并不意味著前一個操作必須要在后一個操作之前執(zhí)行!

happens-before是最終呈現(xiàn)給程序員的視圖,為了實現(xiàn)這個最終的視圖,需要JMM實現(xiàn)時禁止某些編譯器重排序和處理器的重排序。而這個實現(xiàn)的規(guī)則,是JMM定義的。

一個happens-before規(guī)則對應(yīng)于一個或多個編譯器和處理器重排序規(guī)則。

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容