1. 程式人生 > >Java併發機制底層實現原理-synchronized

Java併發機制底層實現原理-synchronized

章節目錄

  • synchronized的實現原理與應用

synchronized 重量級鎖

1.6版本之前 synchronized 被稱之為 重量級鎖
1.6版本對 synchronized 進行了優化,主要優化的點在於 減少 獲得鎖和釋放鎖帶
來的效能消耗,為實現這個目的引入了偏向鎖、與輕量級鎖。 

synchronized 實現同步的基礎

Java中每一個物件都可以作為鎖。
普通同步方法,鎖是當前例項物件。
靜態同步方法塊,鎖是當前類的Class物件。
對於同步方法塊,鎖是synchronized括號裡配置的物件。

synchronized 同步鎖的獲取 底層原理
如下圖所示:

2836699-fdb6d9bb82b6fdf3.png synchronized 同步鎖的獲取 底層原理.png
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 執行緒阻塞,響應時間緩慢 追求吞吐量,同步塊執行速度較長