掌握高併發、高可用架構
第二課 併發編程
從本課開始學習併發編程的內容。主要介紹併發編程的基礎知識、鎖、內存模型、線程池、各種併發容器的使用。
第六節 JAVA內存模型
JMM
內存模型
Java內存模型(Java Memory Model)規範了Java虛擬機與計算機內存是如何協同工作的。對於開發併發程序,理解Java內存模型是非常重要的。它規定了如何和何時可以看到由其他線程修改過的共享變量的值,以及在必要時如何同步的訪問共享變量。
JMM內部原理
JMM把JVM內部劃分爲線程棧和堆。
每個運行在JVM中的線程都擁有自己的線程棧,這個線程棧包含了這個線程調用的方法當前執行點的相關信息。一個線程僅能訪問自己的線程棧,線程創建的本地變量對其他線程不可見。
堆上包含Java程序中創建的所有對象,無論是哪個對象創建的,包括原始類型的對象版本。
一個原始類型的本地變量,它是在線程棧中的;
一個引用對象類型的本地變量,那麼引用(這個本地變量)是在線程棧中,而引用的對象本身則是在堆中;
一個對象的方法內部的本地變量,仍然是在線程棧中的,即使方法所屬的對象是在堆上;
一個對象的成員變量是在堆上,不管該變量是原始類型還是引用類型;
靜態成員變量跟隨類的定義一起存在堆上;
每個線程都有自己的工作內存,工作內存中保存了線程使用到的主內存中變量的副本
線程對變量的操作(讀取、修改等)都必須在工作內存中進行,不能直接操作主內存
線程之間的值傳遞只能通過主內存來完成;不同線程之間無法訪問對方的工作內存
協議
操作 | 解釋 | 作用域 | 說明 |
---|---|---|---|
lock | 鎖定 | 主內存 | 把一個變量表示爲線程獨佔的狀態 |
unlock | 解鎖 | 主內存 | 把一個變量從線程獨佔的狀態釋放出來,釋放後的變量才能被其他線程鎖定 |
read | 讀取 | 主內存 | 把一個變量從主內存傳輸到工作內存中 |
load | 載入 | 工作內存 | 把read操作的變量值放入工作內存的變量副本中 |
use | 使用 | 工作內存 | 把工作內存中的變量傳遞到執行引擎。當虛擬機遇到需要使用該<br />變量值的字節碼指令時執行此操作 |
assign | 賦值 | 工作內存 | 把執行引擎來的值賦給工作內存的變量。當虛擬機遇到給變量賦值<br />的字節碼指令時執行此操作 |
store | 存儲 | 工作內存 | 把變量的值傳到主內存 |
write | 寫入 | 主內存 | 把store操作的值放到主內存的變量中 |
不允許read和load、store和write單獨出現,即不允許變量從主存讀取了但是工作內存不接受的情況;不允許從工作內存寫回了但主存不接受的情況
不允許一個線程丟棄它最近的assign操作,即變量在工作內存修改後,就必須同步回主存
不允許一個線程無原因的把數據從線程的工作內存同步回主存,即沒有assign就不允許寫回主存
一個新的變量只能在主存中創建,不允許在工作內存中使用一個違背初始化的變量,即要use必須load,要store必須assign
一個變量在同一時刻只允許一個線程進行lock,但一個線程可以執行多次lock操作,多次lock後,必須執行相同次數的unlock,變量才能解鎖
沒有lock就不能unlock,也不允許unlock由其他線程鎖住的變量
對變量unlock時,必須先把變量同步回主存,即store、wirte