Java記憶體模型最全詳解(5大模型圖解)

張哥說技術發表於2024-01-26


大家好,我是mikechen


Java記憶體模型經常在Java面試被問到,比如:Java記憶體模型作用與實現等,下面重點詳解Java記憶體模型@mikechen


Java記憶體模型

Java記憶體模型,全稱Java Memory Model,簡稱JMM,是Java程式執行時記憶體的抽象概念,描述了Java程式如何在記憶體中儲存和訪問資料。

Java記憶體模型定義了一些規則和原則,比如:規定了執行緒如何與記憶體進行互動,包括執行緒之間的同步和資料共享,作用就是:確保程式的正確性和一致性。

 

Java記憶體模型實現

Java記憶體模型中主要包括以下內容:

1.主記憶體(Main Memory)

Java記憶體模型中的主記憶體(Main Memory)是所有執行緒共享的記憶體區域,用於儲存Java程式中的變數和物件例項等資料。

如下圖黃色部分所示:

Java記憶體模型最全詳解(5大模型圖解)

所有的變數都儲存在主記憶體中,包括靜態變數、例項變數和陣列元素等。

主記憶體可以被所有執行緒訪問,但執行緒不能直接訪問主記憶體中的變數。

只能透過將主記憶體中的變數讀取到自己的工作記憶體中,或將自己工作記憶體中的變數寫回主記憶體中,來實現對主記憶體的訪問。

在Java記憶體模型中,主記憶體具有以下特點:

  1. 所有執行緒都可以訪問主記憶體中的資料。

  2. 主記憶體中的資料是執行緒間共享的,因此在多執行緒環境下,需要使用同步機制來保證資料的一致性。

  3. 主記憶體中的資料可以被多個執行緒同時訪問,但是在同一時刻只能被一個執行緒修改。

  4. 主記憶體中的資料對於所有執行緒都是可見的,即當一個執行緒修改了主記憶體中的資料後,其他執行緒可以立即看到這些修改。

因為主記憶體中的資料可以被多個執行緒同時訪問,因此需要使用同步機制來保證多個執行緒對同一資料的訪問順序和正確性。

Java中提供了Synchronized、Volatile、ReentrantLock等同步機制來保證多執行緒程式的正確性和一致性。

2.工作記憶體(Working Memory)

Java記憶體模型中每個執行緒都有自己的工作記憶體(Working Memory),也稱為本地記憶體(Local Memory),用於儲存執行緒執行時需要使用的變數和物件例項等資料。

每個執行緒的工作記憶體都是獨立的,只能透過讀取和寫入自己的工作記憶體來間接訪問主記憶體。

如下圖所示:

Java記憶體模型最全詳解(5大模型圖解)

在Java記憶體模型中,工作記憶體具有以下特點:

  1. 每個執行緒都有自己的工作記憶體,工作記憶體不共享。

  2. 執行緒不能直接訪問主記憶體中的變數和物件例項,只能透過工作記憶體來訪問。

  3. 每個執行緒對變數的操作都是在自己的工作記憶體中進行的,不會影響其他執行緒的操作。

  4. 執行緒之間透過將自己的工作記憶體中的資料寫回主記憶體,或將主記憶體中的資料讀取到自己的工作記憶體來實現資料的共享。

 

3.記憶體間互動操作

Java記憶體模型中,記憶體互動操作是指執行緒間進行資料通訊的操作,包括讀操作、寫操作和鎖定操作等。

如下圖綠色部分,所示:

Java記憶體模型最全詳解(5大模型圖解)

記憶體互動操作可以保證執行緒間對變數的操作順序和正確性,保證多執行緒程式的正確性和一致性。

Java記憶體模型定義了以下記憶體互動操作,主要分為以下8種:

1.lock(鎖定)

lock作用於主記憶體的變數,它把一個變數標識為一條執行緒獨佔的狀態。

2.unlock(解鎖)

unlock作用於主記憶體的變數,它把一個處於鎖定狀態的變數釋放出來,釋放後的變數才可以被其他執行緒鎖定。

3.read(讀取)

read作用於主記憶體的變數,它把一個變數的值從主記憶體傳輸到執行緒的工作記憶體中,以便隨後的load動作使用。

4.load(載入)

load作用於工作記憶體的變數,它把read操作從主記憶體中得到的變數值放入工作記憶體的變數副本中。

5.use(使用)

use作用於工作記憶體的變數,它把工作記憶體中一個變數的值傳遞給執行引擎,每當虛擬機器遇到一個需要使用到變數的值的位元組碼指令時將會執行這個操作。

6.assign(賦值)

assign作用於工作記憶體的變數,它把一個從執行引擎接收到的值賦給工作記憶體的變數,每當虛擬機器遇到一個給變數賦值的位元組碼指令時執行這個操作。

7.store(儲存)

store作用於工作記憶體的變數,它把工作記憶體中一個變數的值傳送到主記憶體中,以便隨後的write操作使用。

8.write(寫入)

write作用於主記憶體的變數,它把store操作從工作記憶體中得到的變數的值放入主記憶體的變數中。

 

4.Happens-Before規則

Java記憶體模型中的Happens-Before規則是指在多執行緒環境下,為了保證程式正確性,程式中的操作需要滿足一定的順序關係,即Happens-Before關係。

Happens-Before規則包括以下幾種:

  1. 程式順序規則(Program Order Rule):對於單個執行緒中的操作,Happens-Before規則保證該執行緒中的每個操作按照程式順序執行,即程式中的操作順序一定是執行緒中的執行順序。

  2. 管程鎖定規則(Monitor Lock Rule):對於一個鎖的解鎖操作,Happens-Before規則保證該鎖的下一個鎖定操作一定能夠看到該鎖的解鎖操作。

  3. volatile變數規則(Volatile Variable Rule):對於一個volatile變數的寫操作,Happens-Before規則保證其他執行緒的讀操作一定能夠看到該變數的更新值。

  4. 傳遞性規則(Transitivity):如果操作A Happens-Before操作B,操作B Happens-Before操作C,那麼操作A Happens-Before操作C。

  5. 執行緒啟動規則(Thread Start Rule):對於一個執行緒的啟動操作,Happens-Before規則保證該執行緒中的操作一定能夠看到主執行緒中在該執行緒啟動之前的操作。

  6. 執行緒終止規則(Thread Termination Rule):對於一個執行緒的終止操作,Happens-Before規則保證該執行緒中的操作一定能夠看到該執行緒在終止之前的操作。

  7. 執行緒中斷規則(Thread Interruption Rule):對於一個執行緒的中斷操作,Happens-Before規則保證該執行緒中的操作一定能夠看到該執行緒在中斷之前的操作。

Happens-Before規則是Java記憶體模型中非常重要的概念,它能夠保證多執行緒程式的正確性和一致性。

 

5.原子性、可見性和有序性

Java記憶體模型中的原子性、可見性和有序性是指多執行緒環境下,程式中的操作需要滿足一定的特性,以保證程式的正確性和一致性。

1.原子性(Atomicity)

原子性指的是一個操作或者多個操作要麼全部執行成功,要麼全部執行失敗,不會出現中間狀態。在Java中,原子性操作可以透過synchronized關鍵字、Lock物件、Atomic包中的原子類等方式來實現。

2.可見性(Visibility)

可見性指的是一個執行緒對共享變數的修改,能夠被其他執行緒立即看到,不會出現資料不一致的情況。在Java中,可見性可以透過volatile關鍵字、synchronized關鍵字等方式來實現。

3.有序性(Ordering)

有序性指的是程式中的操作在執行時按照一定的順序執行,不會出現隨機性和亂序執行的情況。在Java中,有序性可以透過synchronized關鍵字、volatile關鍵字等方式來實現。

在編寫多執行緒程式時,需要同時考慮這三個特性,以保證程式的正確性和一致性。

以上就是Java記憶體模型的詳解,更多Java多執行緒記憶體,請檢視:Java多執行緒程式設計詳解(看這篇就足夠了)


來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70024923/viewspace-3005234/,如需轉載,請註明出處,否則將追究法律責任。