無鎖、自旋鎖、偏向鎖、輕量級鎖和重量級鎖
無鎖
無鎖是指執行緒通過無限迴圈來執行更新操作,如果執行成功就退出迴圈,如果執行失敗(有其他執行緒更新了值),則繼續執行,直到成功為止。CAS操作就屬於無鎖。如果從效能的角度來看,無鎖狀態的效能是非常高的。
自旋鎖
自旋鎖是一種通過讓執行緒不釋放當前的CPU執行一個忙迴圈,來嘗試獲取鎖的方式。自旋鎖的前提假設是鎖被其它執行緒佔用的時間很短。如果其它執行緒佔用鎖的時間很長,那麼自旋的執行緒只會白白消耗處理器資源,而不會做任何有用的工作,反而帶來效能上的浪費。自旋次數的預設值是10
次,使用者可以通過使用引數-XX:PreBlockSpin
來更改。
HotSpot虛擬機器物件頭Mark Word
儲存內容 | 標誌位 | 狀態 |
---|---|---|
物件雜湊碼、物件分代年齡 | 01 |
未鎖定 |
指向鎖記錄的指標 | 00 |
輕量級鎖定 |
偏向執行緒ID、偏向時間戳、物件分代年齡 | 01 |
可偏向 |
指向重量級鎖的指標 | 10 |
膨脹(重量級鎖定) |
空,不需要記錄資訊 | 11 |
GC標記 |
偏向鎖
當一個執行緒獲取了鎖,如果在接下來的執行過程中,該鎖沒有被其它的執行緒獲取,則持有偏向鎖的執行緒將永遠不需要再進行同步。當有另外一個執行緒區嘗試獲取這個鎖的時候,偏向模式就宣告結束。偏向鎖的前提假設是當一個執行緒獲取鎖,後面還有大概率該執行緒還會需要繼續持有這把鎖。
虛擬機器啟用偏向鎖的引數-XX:UseBiasedLocking
。如果當前偏向鎖已啟動,當鎖物件第一次被執行緒獲取的時候,虛擬機器將會把物件頭中的標誌位設為01
輕量級鎖
在程式碼進入同步塊的時候,如果此同步物件沒有被鎖定(鎖標誌位為01
狀態),虛擬機器首先將在當前執行緒的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用於儲存鎖物件目前的Mark Word的拷貝。
然後,虛擬機器將使用CAS操作嘗試將物件的Mark Word更新為指向Lock Record的指標。如果這個更新動作成功了,那麼這個執行緒就擁有了該物件的鎖,並且物件Mark Word的鎖標誌位(Mark Word的最後2bit)將轉變為00
重量級鎖
當有兩個及以上的執行緒爭用同一個鎖,那麼輕量級鎖就不再有效,要膨脹為重量級鎖。鎖標誌的狀態值變為10
,Mark Word中儲存的就是指向重量級鎖(互斥量)的指標,後面等待鎖的執行緒也要進入阻塞狀態。
在討論鎖之間的轉換狀態時,首先需要理解以下幾個問題:
- 偏向鎖只有設定了
-XX:UseBiasedLocking
引數才會存在 - 假設啟用了偏向鎖,物件頭的鎖標誌位是
01
(和未鎖定狀態一樣),但是儲存的內容是偏向執行緒ID、偏向時間戳 - 當執行緒獲取偏向鎖是通過CAS操作將物件頭中儲存的偏向執行緒ID更新為當前執行緒的ID
- 物件是否被鎖定是指物件頭是否指向執行緒的鎖記錄(Lock Record)
- 只有是輕量級鎖或者重量級鎖時物件才會被鎖定
鎖之間狀態轉換
結合自己的理解繪製了一個鎖之間狀態轉化的關係圖: