無鎖、自旋鎖、偏向鎖、輕量級鎖和重量級鎖


無鎖

無鎖是指線程通過無限循環來執行更新操作,如果執行成功就退出循環,如果執行失敗(有其他線程更新了值),則繼續執行,直到成功為止。CAS操作就屬於無鎖。如果從性能的角度來看,無鎖狀態的性能是非常高的。

自旋鎖

自旋鎖是一種通過讓線程不釋放當前的CPU執行一個忙循環,來嘗試獲取鎖的方式。自旋鎖的前提假設是鎖被其它線程占用的時間很短。如果其它線程占用鎖的時間很長,那么自旋的線程只會白白消耗處理器資源,而不會做任何有用的工作,反而帶來性能上的浪費。自旋次數的默認值是10次,用戶可以通過使用參數-XX:PreBlockSpin來更改。

HotSpot虛擬機對象頭Mark Word

存儲內容 標志位 狀態
對象哈希碼、對象分代年齡 01 未鎖定
指向鎖記錄的指針 00 輕量級鎖定
偏向線程ID、偏向時間戳、對象分代年齡 01 可偏向
指向重量級鎖的指針 10 膨脹(重量級鎖定)
空,不需要記錄信息 11 GC標記

偏向鎖

當一個線程獲取了鎖,如果在接下來的執行過程中,該鎖沒有被其它的線程獲取,則持有偏向鎖的線程將永遠不需要再進行同步。當有另外一個線程區嘗試獲取這個鎖的時候,偏向模式就宣告結束。偏向鎖的前提假設是當一個線程獲取鎖,后面還有大概率該線程還會需要繼續持有這把鎖

虛擬機啟用偏向鎖的參數-XX:UseBiasedLocking。如果當前偏向鎖已啟動,當鎖對象第一次被線程獲取的時候,虛擬機將會把對象頭中的標志位設為01,即偏向模式。同時使用CAS操作把獲取到這個鎖的線程的ID記錄在對象的Mark Word之中,如果CAS操作成功,持有偏向鎖的線程以后每次進入這個鎖的同步塊時,虛擬機都可以不用再進行同步操作了。

輕量級鎖

在代碼進入同步塊的時候,如果此同步對象沒有被鎖定(鎖標志位為01狀態),虛擬機首先將在當前線程的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用於存儲鎖對象目前的Mark Word的拷貝。

然后,虛擬機將使用CAS操作嘗試將對象的Mark Word更新為指向Lock Record的指針。如果這個更新動作成功了,那么這個線程就擁有了該對象的鎖,並且對象Mark Word的鎖標志位(Mark Word的最后2bit)將轉變為00,即表示此對象處於輕量級鎖定狀態。輕量級鎖的前提假設是對於絕大部分的鎖,在整個同步周期內都是不存在競爭的,通過CAS操作來避免時候互斥鎖的開銷

重量級鎖

當有兩個及以上的線程爭用同一個鎖,那么輕量級鎖就不再有效,要膨脹為重量級鎖。鎖標志的狀態值變為10,Mark Word中存儲的就是指向重量級鎖(互斥量)的指針,后面等待鎖的線程也要進入阻塞狀態。

在討論鎖之間的轉換狀態時,首先需要理解以下幾個問題:

  • 偏向鎖只有設置了-XX:UseBiasedLocking參數才會存在
  • 假設啟用了偏向鎖,對象頭的鎖標志位是01(和未鎖定狀態一樣),但是存儲的內容是偏向線程ID、偏向時間戳
  • 當線程獲取偏向鎖是通過CAS操作將對象頭中存儲的偏向線程ID更新為當前線程的ID
  • 對象是否被鎖定是指對象頭是否指向線程的鎖記錄(Lock Record)
  • 只有是輕量級鎖或者重量級鎖時對象才會被鎖定

鎖之間狀態轉換

結合自己的理解繪制了一個鎖之間狀態轉化的關系圖:

偏向鎖、輕量級鎖和重量級鎖的狀態轉化及對象Mark Word的關系


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM