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

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中線程的狀態即調度關係如下:


發佈了185 篇原創文章 · 獲贊 63 · 訪問量 146萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章