Java記憶體模型的簡單瞭解
Java記憶體模型即Java Memory Model ,簡稱JMM。JMM定義了Java虛擬機器(JVM)在計算機記憶體(RAM)中的工作方式。JVM是整個計算機虛擬模型,JMM 隸屬於JVM.
JMM 決定一個執行緒對共享變數的寫入何時對另一個執行緒可見。
從抽象的角度看,JMM定義了執行緒和主記憶體之間的抽象關係:執行緒間的共享變數儲存在主記憶體(main memory)中,每個執行緒都有一個私有的本地記憶體(local memory),本地記憶體中儲存了該執行緒用以讀寫的共享變數的副本。
本地記憶體是JMM 的一個抽象概念,並不真實存在。它涵蓋了快取,寫緩衝區,暫存器以及其他的硬體和編譯器優化。
如上圖,執行緒A 與執行緒B 如要通訊
1)執行緒A把本地記憶體A中更新過的共享變數重新整理到主記憶體中去
2)執行緒B到主記憶體中去讀取執行緒A之前已更新過的共享變數
從整體性來看,這兩個步驟實質上是執行緒A向執行緒B 傳送訊息,而且這個通訊過程必須要經過主記憶體。JMM 通過控制主記憶體與各個執行緒的本地記憶體之間的互動,來提供記憶體可見性保證。
Java記憶體模型是一個抽象概念,下面是JVM 對Javan記憶體模型的實現
JVM 對Java記憶體模型的實現
在JVM內部,Java記憶體模型把記憶體分成了兩部分:執行緒棧區和堆區
每一個執行在Java虛擬機器裡的執行緒都擁有自己的執行緒棧。這個執行緒棧包含了這個執行緒呼叫方法當前執行點相關資訊。一個執行緒僅能訪問自己的執行緒棧。一個執行緒棧建立的本地變數對其他執行緒不可見,僅自己可見,即使兩個執行緒執行同樣的程式碼,這兩個執行緒仍然在自己的執行緒棧中的程式碼來建立本地變數。因此每個執行緒擁有每個本地變數的獨有版本。
所有原始型別的本地變數都存放線上程棧上,因此對其他執行緒是不可見的。一個執行緒可能向另一個執行緒傳遞一個原始型別變數的拷貝,但它不能共享這個原始型別變數自身。
堆上包含在Java程式中建立的所有物件,無論是哪個物件建立的,這包括原始型別的物件版本。如果一個物件被建立然後賦值給一個區域性變數,或者用來作為另一個物件的成員變數,這個物件仍然是存放在堆上。
JMM 特性(針對JMM內部)
1)原子性
訪問儲存單元內的任何型別的欄位的值以及對其更新操作時,除開long 型別和double型別,其他型別的欄位必須保證其原子性,這些欄位也包括物件服務的引用。(也可對long 和double 延伸為 volatile long 和volitile double)
2)可見性
該規則定義了一個執行緒在何種情況下可以訪問或影響另一個執行緒。
當一個執行緒需要修改另外一個執行緒的可見單元時需遵守以下原則
- 一個寫入執行緒釋放的同步鎖和緊隨其後進行讀取的讀執行緒的同步鎖是同一個
- 一旦某個欄位被申明為volatile,在任何一個寫入執行緒在工作記憶體重新整理快取之前需要進行進一步的記憶體操作(即針對這樣的欄位立即重新整理)
- 當某個執行緒第一次去訪問某個物件的域時,它要麼初始化該物件的值,要麼從其他寫入執行緒可見域裡面去讀取該物件的值
- 若一個執行緒終止,所有變數值必須從工作記憶體中刷到主存。
3)可排序性
約束任何一個違背了規則呼叫的執行緒在操作過程中的一些順序,排序問題主要圍繞了讀取、寫入和賦值語句有關的序列