Java的內存模型(JMM)

共享變量:

堆內存在線程之間共享。存儲在內存中的所有的實例域、靜態域以及數組元素的共享變量。(局部變量,方法定義參數、異常處理器參數不會在線程之間共享,不會有內存可見性問題,不受內存模型的影響)。

JMM定義了線程和主內存之間的抽象關係:

  1)線程之間的共享變量存儲在主內存(main memory)中

  2)每個線程都有一個私有的本地內存(local memory),本地內存中存儲了該線程用以讀/寫共享變量的副本

  3)本地內存是JMM的一個抽象概念,並不真實存在。它涵蓋了緩存,寫緩衝區,寄存器以及其他的硬件和編譯器優化

線程A與線程B通信:

  1)線程A把本地內存A中更新過的共享變量刷新到主內存中去

  2)線程B到主內存中去讀取線程A之前已更新過的共享變量

JMM通過控制主內存與每個線程的本地內存之間的交互,提供內存可見性保證

 

 

JMM的設計

1)常見的處理器內存模型比JMM要弱,java編譯器在生成字節碼時,會在執行指令序列的適當位置插入內存屏障來限制處理器的重排序。

2)由於各種處理器內存模型的強弱並不相同,爲了在不同的處理器平臺向程序員展示一個一致的內存模型,JMM在不同的處理器中需要插入的內存屏障的數量和種類也不相同。

程序員希望:強內存模型編程,易於理解,易於編程。

編譯器和處理器希望:弱內存模型,內存模型對它們的束縛越少越好,以提高性能

JMM時的核心目標就是找到一個好的平衡點:一方面要爲程序員提供足夠強的內存可見性保證;另一方面,對編譯器和處理器的限制要儘可能的放鬆。

JMM把happens- before要求禁止的重排序分爲了下面兩類:

1)會改變程序執行結果的重排序,JMM要求編譯器和處理器必須禁止這種重排序。

2)不會改變程序執行結果的重排序,JMM對編譯器和處理器不作要求(JMM允許這種重排序)。

  只要不改變程序的執行結果(指的是單線程程序和正確同步的多線程程序),編譯器和處理器怎麼優化都行。

  比如,如果編譯器經過細緻的分析後,認定一個鎖只會被單個線程訪問,那麼這個鎖可以被消除。

  再比如,如果編譯器經過細緻的分析後,認定一個volatile變量僅僅只會被單個線程訪問,那麼編譯器可以把這個volatile變量當作一個普通變量來對待。

  這些優化既不會改變程序的執行結果,又能提高程序的執行效率。

順序一致性內存模型:

順序一致性內存模型是一個被計算機科學家理想化了的理論參考模型,它爲程序員提供了極強的內存可見性保證(JMM沒有順序一致性內存模型保證)。

特性:

1、一個線程中的所有操作必須按照程序的順序來執行。

2、(不管程序是否同步)所有線程都只能看到一個單一的操作執行順序。在順序一致性內存模型中,每個操作都必須原子執行且立刻對所有線程可見。

 

視圖信息:

1.順序一致性模型有一個單一的全局內存

2.在任意時間點最多隻能有一個線程可以連接到內存

3.每一個線程必須按程序的順序來執行內存讀/寫操作

案例:

線程A:A1->A2->A3  線程B:B1->B2->B3  併發執行

正確同步:

 

兩個線程沒有做同步:

 

以上可以得出結論:

1、每個線程內部的執行順序都是按照程序的順序來執行的。

2、所有的線程都只能看到一個線程整體一致的執行順序(原因:順序一致性內存模型中的每個操作必須立即對任意的線程可見)

順序一致性模型與JMM區別:

  順序一致性模型保證單線程內的操作會按程序的順序執行,JMM不保證單線程內的操作會按程序的順序執行(遵守as-if-serial語義)

  順序一致性模型保證所有線程只能看到一致的操作執行順序,而JMM不保證所有線程能看到一致的操作執行順序

JMM在具體實現上的基本方針:在不改變(正確同步的)程序執行結果的前提下,儘可能的爲編譯器和處理器的優化打開方便之門。 

正確同步,JMM保證程序的執行結果將與該程序在順序一致性模型中的執行結果相同(但不保證執行順序)

int a = 0;
bool flag = false;

public void write() {
    a = 2;              //1
    flag = true;        //2
}

public void multiply() {
    if (flag) {         //3
        int ret = a * a;//4
    }
}

 

假設A線程執行writer()方法後,B線程執行reader()方法

處理器內存模型:

如果完全按照順序一致性模型來實現,那麼很多的處理器和編譯器優化都要被禁止,這對執行性能將會有很大的影響。

根據對不同類型讀/寫操作組合的執行順序的放鬆,可以把常見處理器的內存模型劃分爲下面幾種類型:

  1. 放鬆程序中寫-讀操作的順序,由此產生了total store ordering內存模型(簡稱爲TSO)。
  2. 在前面1的基礎上,繼續放鬆程序中寫-寫操作的順序,由此產生了partial store order 內存模型(簡稱爲PSO)。
  3. 在前面1和2的基礎上,繼續放鬆程序中讀-寫和讀-讀操作的順序,由此產生了relaxed memory order內存模型(簡稱爲RMO)和PowerPC內存模型。

注意,這裏處理器對讀/寫操作的放鬆,是以兩個操作之間不存在數據依賴性爲前提的(因爲處理器要遵守as-if-serial語義,處理器不會對存在數據依賴性的兩個內存操作做重排序)。

從上到下,模型由強變弱。越是追求性能的處理器,內存模型設計的會越弱。因爲這些處理器希望內存模型對它們的束縛越少越好,這樣它們就可以做盡可能多的優化來提高性能。

JMM,處理器內存模型,順序一致性內存模型之間的關係

JMM是一個語言級的內存模型,處理器內存模型是硬件級的內存模型,順序一致性內存模型是一個理論參考模型。

語言內存模型,處理器內存模型和順序一致性內存模型的強弱對比示意圖:

 

內存模型越強,越容易保證內存可見性,易編程性就越好。但是重排序就會越少,執行效率就越低。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章