標籤:其他 完成 細節 main 關於 要求 需要 load 資料
Java虛擬機器規範中試圖定義一種Java記憶體模型(Java Memory Model,JMM)來屏蔽掉各種硬體和作業系統的記憶體訪問差異,以實現讓Java程式在各種平台下都能達到一致的記憶體訪問效果。
Java記憶體模型的主要目標是定義程式中各個變數的訪問規則,即在虛擬機器中將變數儲存到記憶體和從記憶體中取出變數這樣的底層細節。
這裡說的變數包括執行個體欄位、靜態欄位和構成數組對象的元素,不包括局部變數與方法參數,因為後者是線程私人的,不會共用,也就不存在競爭的問題。
主記憶體與工作記憶體
Java記憶體模型規定了所有的變數都儲存在主記憶體(Main Memory)中,此外每條線程還有自己的工作記憶體(Working Memory)。
線程的工作記憶體中儲存了被該線程使用到的變數的主記憶體副本拷貝,線程對變數的所有操作(讀取、賦值等)都必須在工作記憶體中進行,不能直接讀寫主記憶體中的變數。
並且,不同的線程之間也無法直接存取對方工作記憶體中的變數,線程間變數值得傳遞均需要通過主記憶體來完成,線程、主記憶體、工作記憶體關係如:
記憶體間的互動動作
關於主記憶體與工作記憶體之間的具體互動協議,即一個變數如何從主記憶體拷貝到工作記憶體、如何從工作記憶體同步到主記憶體之間的實現細節,Java記憶體模型定義了以下八種操作來完成:
- lock(鎖定):作用於主記憶體的變數,把一個變數標識為一條線程獨佔狀態。
- unlock(解鎖):作用於主記憶體變數,把一個處於鎖定狀態的變數釋放出來,釋放後的變數才可以被其他線程鎖定。
- read(讀取):作用於主記憶體變數,把一個變數值從主記憶體傳輸到線程的工作記憶體中,以便隨後的load動作使用
- load(載入):作用於工作記憶體的變數,它把read操作從主記憶體中得到的變數值放入工作記憶體的變數副本中。
- use(使用):作用於工作記憶體的變數,把工作記憶體中的一個變數值傳遞給執行引擎,每當虛擬機器遇到一個需要使用變數的值的位元組碼指令時將會執行這個操作。
- assign(賦值):作用於工作記憶體的變數,它把一個從執行引擎接收到的值賦值給工作記憶體的變數,每當虛擬機器遇到一個給變數賦值的位元組碼指令時執行這個操作。
- store(儲存):作用於工作記憶體的變數,把工作記憶體中的一個變數的值傳送到主記憶體中,以便隨後的write的操作。
- write(寫入):作用於主記憶體的變數,它把store操作從工作記憶體中一個變數的值傳送到主記憶體的變數中。
如果要把一個變數從主記憶體中複製到工作記憶體,就需要按順尋地執行read和load操作,如果把變數從工作記憶體中同步回主記憶體中,就要按順序地執行store和write操作。Java記憶體模型只要求上述操作必須按順序執行,而沒有保證必須是連續執行。也就是read和load之間,store和write之間是可以插入其他指令的,如對主記憶體中的變數a、b進行訪問時,可能的順序是read a,read b,load b, load a。Java記憶體模型還規定了在執行上述八種基本操作時,必須滿足如下規則:
- 不允許read和load、store和write操作之一單獨出現
- 不允許一個線程丟棄它的最近assign的操作,即變數在工作記憶體中改變了之後必須同步到主記憶體中。
- 不允許一個線程無原因地(沒有發生過任何assign操作)把資料從工作記憶體同步回主記憶體中。
- 一個新的變數只能在主記憶體中誕生,不允許在工作記憶體中直接使用一個未被初始化(load或assign)的變數。即就是對一個變數實施use和store操作之前,必須先執行過了assign和load操作。
- 一個變數在同一時刻只允許一條線程對其進行lock操作,lock和unlock必須成對出現
- 如果對一個變數執行lock操作,將會清空工作記憶體中此變數的值,在執行引擎使用這個變數前需要重新執行load或assign操作初始設定變數的值
- 如果一個變數事先沒有被lock伺服器用戶端檔案鎖,則不允許對它執行unlock操作;也不允許去unlock一個被其他線程鎖定的變數。
- 對一個變數執行unlock操作之前,必須先把此變數同步到主記憶體中(執行store和write操作)。
java記憶體模型