Java併發機制底層實現原理-synchronized
阿新 • • 發佈:2019-02-09
章節目錄
- synchronized的實現原理與應用
synchronized 重量級鎖
1.6版本之前 synchronized 被稱之為 重量級鎖
1.6版本對 synchronized 進行了優化,主要優化的點在於 減少 獲得鎖和釋放鎖帶
來的效能消耗,為實現這個目的引入了偏向鎖、與輕量級鎖。
synchronized 實現同步的基礎
Java中每一個物件都可以作為鎖。
普通同步方法,鎖是當前例項物件。
靜態同步方法塊,鎖是當前類的Class物件。
對於同步方法塊,鎖是synchronized括號裡配置的物件。
synchronized 同步鎖的獲取 底層原理
如下圖所示:
synchronized鎖的儲存位置
synchronized 用的鎖是存在java物件頭裡的。
物件頭中的Mark-word 預設儲存物件的hashcode、分代年齡、和鎖標誌位。
Mark-word 中儲存的資料會隨著鎖標誌位的變化而變化
輕量級鎖-00
重量級鎖-10
GC標記-11
偏向鎖-01
鎖的升級與對比
Java SE 1.6 當中鎖一共有4種狀態,級別從低到高一次為:無鎖狀態、偏向鎖狀態、輕量級鎖狀態、重量級鎖狀態。鎖可以升級但不能降級,這種鎖升級但不能降級的策略,目的是為了提高獲得鎖與釋放鎖的效率。
1.偏向鎖原理
偏向鎖的優點及初始化過程:
- 加鎖解鎖不需要額外的資源消耗,只需要對比當前執行緒id在物件頭中是否儲存指向當前執行緒的偏向鎖。如果存在,表示當前執行緒已經獲得鎖。如果測試失敗,則查詢當前mark word中的偏向鎖標誌是否設定成為1,如果沒有設定,則使用CAS競爭鎖(非偏向鎖狀態),如果設定了偏向鎖標誌,則嘗試使用CAS將物件頭的偏向鎖指向當前執行緒。
偏向鎖的撤銷:
- 偏向鎖使用了一種等到競爭出現才釋放鎖的機制,當其他執行緒嘗試競爭偏向鎖的時候,持有偏向鎖的執行緒才會釋放鎖。偏向鎖的撤銷,需要等待全域性安全點,這個時間點上沒有正在執行的位元組碼。它首先會暫停擁有偏向鎖的執行緒,然後檢查持有偏向鎖的執行緒活著,如果執行緒不處於活動狀態,則將物件頭設定為無鎖狀態。如果執行緒仍活著,擁有偏向鎖的棧會被執行完。
2.輕量級鎖原理
輕量級鎖加鎖:
- 執行緒在執行同步塊之前,JVM會先在當前執行緒的棧楨中建立儲存鎖記錄的空間,並將物件頭中的mark word 複製到鎖記錄當中,然後執行緒嘗試使用CAS將物件頭中的 mark word 替換為指向鎖記錄的指標。如果成功,當前執行緒獲得鎖,如果失敗,表示其他執行緒競爭鎖,當前執行緒便嘗試使用自旋鎖來獲取鎖。
輕量級鎖解鎖
- 輕量級解鎖時,會使用原子的CAS將鎖記錄(Displaced Mark Word)替換回到
物件頭,如果成功,則表示沒有發生競爭。如果失敗,表示當前鎖存在競爭,鎖就會膨脹為重量級鎖。
總結
鎖 | 優點 | 缺點 | 適用場景 |
---|---|---|---|
偏向鎖 | 加鎖和解鎖都不需要額外的消耗,和執行非同步的方法相比只存在納秒級差距 | 如果執行緒間存在鎖競爭,會帶來額外的鎖撤銷的消耗 | 適用於只有一個執行緒訪問同步塊的場景 |
輕量級鎖 | 競爭的執行緒不會阻塞,提高了應用的相應速率 | 如果始終得不到競爭的執行緒,適用自旋會消耗cpu,造成cpu空轉 | 追求響應時間,同步塊執行速度非常快 |
重量級鎖 | 執行緒競爭不使用自旋,不會消耗cpu | 執行緒阻塞,響應時間緩慢 | 追求吞吐量,同步塊執行速度較長 |
不同鎖的優缺點
鎖 | 優點 | 缺點 | 適用場景 |
---|---|---|---|
偏向鎖 | 加鎖和解鎖都不需要額外的消耗,和執行非同步的方法相比只存在納秒級差距 | 如果執行緒間存在鎖競爭,會帶來額外的鎖撤銷的消耗 | 適用於只有一個執行緒訪問同步塊的場景 |
輕量級鎖 | 競爭的執行緒不會阻塞,提高了應用的相應速率 | 如果始終得不到競爭的執行緒,適用自旋會消耗cpu,造成cpu空轉 | 追求響應時間,同步塊執行速度非常快 |
重量級鎖 | 執行緒競爭不使用自旋,不會消耗cpu | 執行緒阻塞,響應時間緩慢 | 追求吞吐量,同步塊執行速度較長 |