??????????JMM?? 是Java虛擬機(JVM)規范中定義的一組規則和規范,用于描述多線程環境下,Java程序中變量的訪問和修改行為,尤其是在并發編程中如何保證內存可見性、原子性和有序性。JMM 是 Java 并發編程的基石,它定義了線程之間如何通過內存進行交互,確保程序在不同平臺和處理器架構上具有一致的并發行為。(JMM保證了java并發編程的跨平臺)
一、JMM 的核心目標
JMM 的主要目標是解決多線程環境下的三個核心問題:
-
??原子性(Atomicity)?:?保證某些操作是不可分割的,要么全部執行,要么全部不執行,不會被其他線程干擾。
-
??可見性(Visibility)?:?當一個線程修改了共享變量的值后,其他線程能夠立即看到這個修改。
-
??有序性(Ordering)?:?程序執行的順序按照代碼的先后順序執行,避免指令重排序導致的邏輯錯誤。
二、JMM 的基本概念
1. 主內存與工作內存(重點)
JMM 抽象了線程與主內存之間的關系:
-
??主內存(Main Memory)??:所有線程共享的內存區域,存儲所有的實例變量、靜態變量等。可以類比為計算機中的物理內存。
-
??工作內存(Working Memory)??:每個線程都有自己的工作內存(類似于CPU的寄存器或緩存),線程從主內存中讀取變量到自己的工作內存中進行操作,操作完成后再將結果寫回主內存。工作內存是線程私有的,線程之間不能直接訪問彼此的工作內存。
2. 內存間的交互操作(不是重點)
JMM 定義了八種原子操作,用于線程與主內存之間的交互:
- ??lock(鎖定)??:作用于主內存的變量,將一個變量標識為一條線程獨占的狀態。
- ??unlock(解鎖)??:作用于主內存的變量,釋放一個變量的鎖定狀態。
- ??read(讀取)??:作用于主內存的變量,將一個變量的值從主內存傳輸到線程的工作內存,以便隨后的load操作。
- ??load(載入)??:作用于工作內存的變量,將read操作得到的值放入工作內存的變量副本中。
- ??use(使用)??:作用于工作內存的變量,將工作內存中的一個變量的值傳遞給執行引擎,每當虛擬機遇到一個需要使用變量的字節碼指令時就會執行這個操作。
- ??assign(賦值)??:作用于工作內存的變量,將執行引擎接收到的值賦給工作內存的變量,每當虛擬機遇到一個給變量賦值的字節碼指令時執行這個操作。
- ??store(存儲)??:作用于工作內存的變量,將工作內存中的一個變量的值傳送到主內存中,以便隨后的write操作。
- ??write(寫入)??:作用于主內存的變量,將store操作得到的值放入主內存的變量中。
這些操作必須按特定的規則組合執行,以確保內存操作的原子性、可見性和有序性。
三、JMM 與 Java 并發編程的關系
????????JMM 為 Java 并發編程提供了一套規范,確保在多線程環境下程序的行為是可預測和一致的。它通過定義內存屏障(Memory Barriers)、happens-before 關系等機制,來控制線程間的內存可見性和操作順序。
1. Happens-Before 原則
??Happens-Before?? 是 JMM 中的一個核心概念,用于判斷兩個操作之間的執行順序。如果操作A happens-before 操作B,那么操作A的結果對操作B可見,并且操作A在操作B之前執行。
JMM 定義了以下幾種 Happens-Before 關系:
-
??程序次序規則(Program Order Rule)??
在同一個線程中,按照程序代碼的順序,前面的操作 happens-before 后面的操作。 -
??鎖定規則(Monitor Lock Rule)??
一個線程解鎖操作 happens-before 另一個線程對同一個鎖的加鎖操作。 -
??volatile 變量規則(Volatile Variable Rule)??
對一個 volatile 變量的寫操作 happens-before 后續對這個變量的讀操作。 -
??線程啟動規則(Thread Start Rule)??
Thread 對象的?start()
?方法調用 happens-before 啟動線程中的任何操作。 -
??線程終止規則(Thread Termination Rule)??
線程中的任何操作 happens-before 其他線程檢測到該線程已經終止(通過?Thread.join()
?方法或?Thread.isAlive()
?返回 false)。 -
??線程中斷規則(Thread Interruption Rule)??
對線程?interrupt()
?方法的調用 happens-before 被中斷線程檢測到中斷事件(通過?Thread.interrupted()
?或?Thread.isInterrupted()
)。 -
??對象終結規則(Finalizer Rule)??
一個對象的初始化完成 happens-before 它的?finalize()
?方法的開始。 -
??傳遞性(Transitivity)??
如果操作A happens-before 操作B,且操作B happens-before 操作C,那么操作A happens-before 操作C。
??????????Happens-Before原則幫助開發者理解和推斷多線程程序中的內存可見性和操作順序,從而編寫出正確且高效的并發代碼。
2. 內存屏障(Memory Barriers)
????????雖然 JMM 在規范層面定義了 Happens-Before 關系,但在實際實現中,JVM 會通過插入??內存屏障??來保證這些關系。內存屏障是一種硬件或軟件機制,用于控制指令的執行順序和內存訪問的順序,防止指令重排序和保證內存可見性。
常見的 memory barriers 包括:
屏障類型 | 作用 | 說明 |
---|---|---|
??LoadLoad 屏障?? | 確保 Load1 的數據加載先于 Load2 及后續的加載操作 | 防止 Load2 讀取到比 Load1 更舊的數據 |
??StoreStore 屏障?? | 確保 Store1 的數據存儲先于 Store2 及后續的存儲操作 | 防止 Store2 覆蓋 Store1 的數據 |
??LoadStore 屏障?? | 確保 Load1 的數據加載先于 Store2 及后續的存儲操作 | 防止 Store2 存儲的數據比 Load1 讀取的數據更舊 |
??StoreLoad 屏障?? | 確保 Store1 的數據存儲先于 Load2 及后續的加載操作 | 防止 Load2 讀取到比 Store1 更舊的數據(最耗性能) |
????????這些屏障在不同的處理器架構上有不同的實現方式,JVM 會根據目標平臺插入相應的屏障指令,以保證 JMM 的語義。
四、JMM 與 Java 關鍵字的關系
????????Java 提供了一些關鍵字和工具來幫助開發者控制內存可見性和線程同步,這些機制在底層依賴于 JMM 的規范。