文章基於jdk1.7,通過學習《Java併發程式設計的藝術》,對Java記憶體模型的理解
併發程式設計模型的兩個關鍵問題
- 執行緒之間如何通訊
- 執行緒之間如何同步
上面所說的執行緒指的是併發執行的活動實體。
執行緒之間的通訊機制有兩種:共享記憶體
和訊息傳遞
- 在共享記憶體的併發模型中,執行緒之間共享程式的公共狀態,通過寫-讀記憶體中的公共狀態進行隱式通訊
- 在訊息傳遞的併發模型中,執行緒之間沒有公共狀態,必須通過傳送訊息來顯式進行通訊
同步無非就是控制不同執行緒的執行順序。在共享記憶體的併發模型中,同步是顯式進行的,程式設計師必須顯式的指定某個方法或者某段程式碼需要線上程之間互斥執行。在訊息傳遞的併發模型中,同步是隱式的,因為訊息的傳送必須在訊息的接收之間。
Java的併發採用的是共享記憶體模型,Java執行緒之間的通訊總是隱式進行的,整個通訊過程對程式設計師完全透明。
Java記憶體模型的抽象結構
在Java中,所有例項域、靜態域和陣列元素都儲存在堆記憶體中,堆記憶體線上程之間共享。區域性變數和異常處理器引數不會線上程之間共享,它們不會有記憶體可見性問題,也不會受記憶體模型的影響。
Java執行緒之間的通訊由Java記憶體模型
(JMM)控制,JMM決定一個執行緒對共享變數的寫入何時對另一個執行緒可見。
抽象來說,JMM定義了執行緒和主記憶體之間的抽象關係:執行緒之間的共享變數儲存在主記憶體中,每個執行緒都有一個私有的本地記憶體,本地記憶體中儲存了該執行緒以讀/寫共享變數的副本,本地記憶體只是JMM的一個抽象概念,並不真實的存在。它涵蓋了快取、寫緩衝區、暫存器以及其他的硬體和編譯器優化。
JMM的抽象示意圖如下:
從上圖來看,如果執行緒A和執行緒B要通訊的話,需要經過兩個步驟:- 執行緒A把本地記憶體A中更新過的共享變數重新整理到主記憶體中去
- 執行緒B到主記憶體中去讀取執行緒A之前已更新過的共享變數
JMM通過控制主記憶體和每個執行緒的本地記憶體之間的互動,來為Java程式實現記憶體可見性的保證。
JMM和JVM的區別
JMM中的主記憶體、工作記憶體與JVM中的Java堆、棧、方法區等並不是同一個層次的記憶體劃分,這兩者基本上是沒有關係的,如果兩者一定要勉強對應起來,那從變數、主記憶體、工作記憶體的定義來看,主記憶體主要對應於Java堆中的物件例項資料部分,而工作記憶體則對應於虛擬機器棧中的部分割槽域。從更底層次上說,主記憶體就直接對應於物理硬體的記憶體,而為了獲取更好的執行速度,虛擬機器(甚至是硬體系統本身的優化措施)可能會讓工作記憶體優先儲存於暫存器和快取記憶體中,因為程式執行時主要訪問讀寫的是工作記憶體。
歡迎關注我的公眾號哦~
搜尋公眾號:翻身碼農把歌唱 或者 掃描下方二維碼: