【Java虛擬機器】Java記憶體模型與執行緒
阿新 • • 發佈:2018-12-03
Java記憶體模型與執行緒
Java記憶體模型
- 所有的變數都儲存在主記憶體中。
- 每條執行緒都有自己的工作記憶體。
- 執行緒的工作記憶體儲存了被該執行緒使用到的變數的主記憶體副本拷貝。
- 執行緒對變數的所有操作都必須在工作記憶體中進行,不能直接讀寫主記憶體的變數
執行緒、主記憶體、工作記憶體三者的互動關係如下圖所示:
記憶體間互動操作
- lock:作用於主記憶體的變數,它把一個變數標識為一條執行緒獨佔的狀態。
- unlock:作用於主記憶體的變數,它把一個處於鎖定狀態的變數釋放出來,釋放後的變數才可以被其他執行緒鎖定。
- read:作用於主記憶體的變數,它把一個變數的值從主記憶體傳輸到執行緒的工作記憶體中,以便隨後的load動作使用。
- load:作用於工作記憶體的變數,它把read操作從主記憶體中得到的變數值放入工作記憶體的變數副本中。
- use:作用於工作記憶體的變數,它把工作記憶體中一個變數的值傳遞給執行引擎,每當虛擬機器遇到一個需要使用到變數的值的位元組碼指令時將會執行這個操作。
- assign:作用於工作記憶體的變數,它把一個從執行引擎接收到的值賦給工作記憶體的變數,每當虛擬機器遇到一個給變數賦值的位元組碼指令時執行這個操作。
- store:作用於工作記憶體的變數,它把工作記憶體中一個變數的值傳送到主記憶體中,以便隨後的write操作使用。
- write:作用於主內粗你的變數,它把store操作從工作記憶體中得到的變數的值放入主記憶體的變數中。
volatile關鍵字
- 可見性:使用前必須先從主記憶體重新整理最新的值,修改變數之後必須立刻同步會主記憶體中
- 禁止指令重排序優化
Java與執行緒
核心實現
核心執行緒(Kernel-Level Thread,KLT)直接由作業系統核心支援的執行緒,由核心來完成執行緒切換,核心通過操縱排程器對執行緒進行排程,並負責將執行緒的任務對映到各個處理器上。
程式一般使用核心執行緒的一種高階介面——輕量級程序(Light Weight Process,LWP),每個輕量級程序都有一個核心執行緒支援。
輕量級程序與核心執行緒之間的關係如下圖所示:
使用使用者執行緒實現
使用者執行緒的建立、同步、銷燬和排程完全在使用者態中完成,不需要核心的幫助。
所有的執行緒操作都需要使用者程式自己處理。執行緒的建立、切換和排程都是需要考慮的問題,而且由於作業系統只把處理器資源分配的程序,那諸如“阻塞如何處理”、“多處理器系統中如何將執行緒對映到其他處理器”這類問題解決起來將會異常困難,甚至不可能完成。
程序與使用者執行緒之間的關係如下圖所示:
使用使用者執行緒加輕量級程序混合實現
這種混合實現下,既存在使用者執行緒,也存在輕量級程序。使用者執行緒還是完全建立在使用者空間中,輕量級程序則作為使用者執行緒和核心執行緒之間的橋樑。
使用者執行緒與輕量級程序之間的關係如下圖所示:
Java執行緒的實現
不同的平臺,採用不同的執行緒模型。
Windows版和linux版都是使用核心實現的。
Solaris平臺,支援核心實現的內執行緒模型和使用者執行緒加輕量級執行緒的執行緒模型,可以根據引數來選擇一種執行緒模型。
Java執行緒排程
- 協同式執行緒排程:執行緒的執行時間由執行緒本身來控制,執行緒把自己的工作執行完了之後,要主動通知系統切換到另一個執行緒上。
- 搶佔式執行緒排程:每個執行緒由系統來分配時間,執行緒的切換不由執行緒本身決定。
Java採用的是搶佔式排程。
狀態轉換
Java語言定義了5種執行緒狀態,在任意一個時間點,一個執行緒只能有且只有其中的一種狀態
- 新建(New):建立後尚未啟動的執行緒處於這種狀態。
- 執行(Runable):Runable包括了作業系統執行緒狀態中的Running和Ready,也就是處於此狀態的執行緒有可能正在執行,也有可能正在等待CPU為它分配執行時間
- 無限期等待(Waiting):處於這種狀態的執行緒不會分配CPU時間,他們要等待被其他執行緒顯示地喚醒。比如:object.wait()、thread.join()
- 期限等待(Timed Waiting):處於這種狀態的執行緒也不會分配CPU時間,不過無需等待被其他執行緒顯示地喚醒,在一定時間之後它們會有系統自動喚醒。比如:thread.sleep(millis)、object.wait(timeout)、thread.join(millis)
- 阻塞(blocked):執行緒被阻塞了,等待進入同步區域的時候,執行緒將進入這種狀態。
- 結束(Terminated):已終止執行緒的執行緒狀態,執行緒已經結束執行
執行緒狀態狀態如下圖所示:
參考
- 深入理解Java虛擬機器[書籍]