1. 程式人生 > >第13章執行緒安全與鎖優化

第13章執行緒安全與鎖優化

執行緒安全

當多個執行緒訪問一個物件的時候,如果不用考慮這些執行緒在執行時環境下的排程和交替執行,也不需要進行額外的同步,或者在呼叫方進行任何其他的協調操作,呼叫這個物件的行為都可以獲得正確的結果,那這個物件時執行緒安全的

Java語言中各種操作共享的資料分為以下五類:

  1. 不可變:用final來修飾一個基本資料型別或是物件所在的類
  2. 絕對執行緒安全:在Java API中標註自己是執行緒安全的類,大多數都不是絕對的執行緒安全
  3. 相對執行緒安全:即通常所說的執行緒安全,代表類:Vector,HashTable,Collections的synchronizedCollection()方法
  4. 執行緒相容:即通常所說的執行緒不安全,代表類:ArrayList和HashMap
  5. 執行緒對立:指呼叫段是否採取了同步措施,都無法在多執行緒環境中併發使用的程式碼,代表:Thread類的suspend()和resume()方法

執行緒安全的實現方法:

  1. 互斥同步(阻塞同步):對執行緒進行頻繁的阻塞和喚醒會帶來效能問題,屬於一種悲觀的併發策略。
  2. 非阻塞同步(通過處理器指令集實現,代表:CAS),是一種樂觀併發策略,先進行操作,如果沒有其他執行緒爭用共享資料,那操作就成功了,如果共享資料由爭用,產生了衝突,那就再採取其他的補償措施(如不斷地重試,直到成功為止),這種方法不需要把執行緒掛起。
  3. 無同步方案:如果一個方法本身就不涉及共享資料,自然無需同步措施去保證正確性,天生是執行緒安全的程式碼分為兩類:可重入程式碼執行緒本地儲存

什麼是可重入程式碼:相對於執行緒安全的特性來說,可重入性是更基本的特性,它可以保證執行緒安全;但是反過來,執行緒安全並不保證可重入性

執行緒本地儲存:把共享資料的可見範圍限制在同一個執行緒之內,如ThreadLocal類實現執行緒本地儲存功能

ReentrantLock與synchronized都具有互斥的特點用來實現同步,不過reentrantLock具有以下三個高階功能

  1. 等待可中斷:當持有鎖的執行緒長期不釋放鎖的時候,正在等待的執行緒可以選擇放棄等待,改為處理其他的事情,對執行時間非常長的同步塊很有用
  2. 可實現公平鎖:多個執行緒等待同一個鎖時,必須按照申請鎖的時間順序來一次獲得鎖,而非公平鎖則不保證這一點,在鎖被釋放的時候,任何一個等待鎖的執行緒都有機會獲得鎖
  3. 鎖可以繫結多個條件:一個ReentrantLock物件可以同時繫結多個Condition物件

ReentrantLock的弊端:吞吐量不如synchronized

CAS指令需要3個運算元,分別是記憶體位置(V),舊的預期值(A),新值(B)。CAS 指令執行的時候,當且僅當V符合舊預期值A時,處理器用新值B更新V值,否則它就不執行更新,但是無論是否更新了V的值,都會返回V的舊值。這個操作是一個原子操作

第三節 鎖優化

自旋鎖:JDK1.6預設開啟自旋鎖,因為掛起和恢復執行緒的操作都需要轉入核心態來完成,這樣會給系統的效能帶來很大的壓力,特別是在共享資料的鎖定狀態只維持很短的時間的情況下,因此引出了自旋鎖是在有兩個以上的處理器的情況下,讓多個執行緒同時工作,如果後面的執行緒請求鎖,就讓它稍等一下,但不放棄處理器的執行時間,這時會讓該執行緒執行一個忙迴圈。

鎖粗化:一般情況下推薦獎程式碼塊的作用範圍限制的儘量小,這是做細化,但是如果一系列的連續操作都對同一物件進行反覆加鎖,解鎖,甚至加鎖操作是出現在迴圈體中的,那即使沒有執行緒競爭,頻繁地進行互斥同步操作也會導致不必要的效能損耗。通常情況下,將加鎖同步的範圍擴大到整個操作序列的外部。

輕量級鎖:JDK1.6新增的鎖機制,在沒有多執行緒競爭的前提下,減少傳統重量級鎖使用作業系統互斥量產生的效能損耗。