《深入理解java虛擬機器》學習筆記10——併發程式設計(二)

yangxi_001發表於2013-12-04

Java的併發程式設計是依賴虛擬機器記憶體模型的三個特性實現的:

(1).原子性(Atomicity):

原子性是指不可再分的最小操作指令,即單條機器指令,原子性操作任意時刻只能有一個執行緒,因此是執行緒安全的。

Java記憶體模型中通過read、load、assign、use、store和write這6個操作保證變數的原子性操作。

long和double這兩個64位長度的資料型別java虛擬機器並沒有強制規定他們的read、load、store和write操作的原子性,即所謂的非原子性協定,但是目前的各種商業java虛擬機器都把long和double資料型別的4中非原子性協定操作實現為原子性。所以java中基本資料型別的訪問讀寫是原子性操作。

對於大範圍的原子性保證需要通過lock和unlock操作以及synchronized同步塊來保證。

(2).可見性(Visibility):

可見性是指當一個執行緒修改了共享變數的值,其他執行緒可以立即得知這個修改。

Java記憶體模型是通過在變數修改後將新值同步回主記憶體,在變數讀取前從主記憶體重新整理變數值來實現可見性的。

Java中通過volatile、final和synchronized這三個關鍵字保證可見性:

volatile:通過重新整理變數值確保可見性。

synchronized:同步塊通過變數lock鎖定前必須清空工作記憶體中變數值,重新從主記憶體中讀取變數值,unlock解鎖前必須把變數值同步回主記憶體來確保可見性。

final:被final修飾的欄位在構造器中一旦被初始化完成,並且構造器沒有把this引用傳遞進去,那麼在其他執行緒中就能看見final欄位的值,無需同步就可以被其他執行緒正確訪問。

(3).有序性(Ordering):

執行緒的有序性是指:線上程內部,所有的操作都是有序執行的,而線上程之間,因為工作記憶體和主記憶體同步的延遲,操作是亂序執行的。

Java通過volatile和synchronized關鍵字確保執行緒之間操作的有序性。

volatile禁止指令重排序優化實現有序性。

synchronized通過一個變數在同一時刻只允許一個執行緒對其進行lock鎖定操作來確保有序性。

JDK執行緒的實現如下:

(1).Kernal thread:KLT,核心執行緒,執行在核心態,是直接有作業系統核心支援的執行緒,有作業系統核心完成核心執行緒切換,核心操作執行緒排程器Threadscheduler對核心執行緒進行排程,負責將核心執行緒任務對映到各個處理器上。

(2).Light weight process: LWP,輕量級使用者程式,是程式設計中傳統意義上的執行緒,每個輕量級程式都由一個核心執行緒支援。

(3).User thread:UT,使用者執行緒,執行在使用者態,完全由使用者空間執行緒庫實現,核心執行緒無法感知到使用者執行緒的實現,使用者執行緒的建立、同步、排程和銷燬完全在使用者態中完成,不需要核心態的支援。

JDK的執行緒是基於作業系統原生執行緒模型來實現的,因此JDK版本中執行緒模型取決於java虛擬機器執行緒與作業系統執行緒的對映,在不同平臺上是不同的。

執行緒排程有兩種方式:

(1).協同式:執行緒的執行時間由執行緒本身來控制,執行緒任務執行完成之後主動通知系統切換到另一個執行緒去執行。

優點:實現簡單,執行緒切換操作對執行緒本身是可知的,不存線上程同步問題。

缺點:執行緒執行時間不可控制,如果執行緒長時間執行不讓出CPU執行時間可能導致系統崩潰。

(2).搶佔式:每個執行緒的執行時間有作業系統來分配,作業系統給每個執行緒分配執行的時間片,搶到時間片的執行緒執行,時間片用完之後重新搶佔執行時間,執行緒的切換不由執行緒本身來決定。

優點:執行緒執行時間可控制,不會因為一個執行緒阻塞問題導致系統崩潰。

 

當前JDK的多執行緒是搶佔式的多執行緒系統,但是可以通過設定執行緒優先順序和改變執行緒的執行時間分配概率。

注意:由於JDK的執行緒優先順序和作業系統的執行緒優先順序不是一一對應的,因此建議只使用1(最低優先順序)、5(正常優先順序)和10(最高優先順序)這三個優先順序。

另外,執行緒優先順序只是作業系統給執行緒分配執行時間的概率大小,不是絕對的。

Java中執行緒的狀態即排程關係如下:

相關文章