無鎖
無鎖是指執行緒通過無限回圈來執行更新操作,如果執行成功就退出回圈,如果執行失敗(有其他執行緒更新了值),則繼續執行,直到成功為止,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)
- 只有是輕量級鎖或者重量級鎖時物件才會被鎖定
鎖之間狀態轉換
結合自己的理解繪制了一個鎖之間狀態轉化的關系圖:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/145064.html
標籤:Java
上一篇:Java并發編程實踐
