synchronized原理學習筆記

Tomax發表於2019-02-09

synchronized 是Java併發程式設計中非常重要的角色,這裡簡單記錄對於其原理的學習

基礎內容

  • synchronized 具有互斥性,可以保證只有一個執行緒可以訪問同步塊

  • synchronized 修飾普通方法,鎖為當前例項物件

  • synchronized 修飾靜態方法,鎖為當前類的Class物件

  • synchronized 修飾同步方法塊,鎖為程式碼塊括號中填寫的物件

指令實現

  • 同步程式碼塊通過monitorentermonitorexit兩條指令控制同步程式碼塊的訪問
  • 同步方法通過設定ACC_SYNCHRONIZED標誌符控制(也可以通過上述兩條指令來實現)

所有Java物件都會有一個monitor,當monitor被持有後,物件就處於鎖定狀態。當執行到monitorenter指令時,執行緒會嘗試獲取物件的monitor,而執行monitorexit後會釋放物件的monitor

Java SE 1.6為了降低鎖的獲取、釋放造成的效能損耗,增加了偏向鎖、輕量級鎖。鎖的級別由高到低依次為無鎖狀態、偏向鎖、輕量級鎖、重量級鎖,鎖可以升級,但不可以降級

偏向鎖

內容

鎖由同一執行緒多次獲取時,會在物件頭中記錄執行緒ID,並在之後對同步塊的訪問時,不需要進行CAS操作來加鎖、解鎖。

Mark Word狀態

Mark Word記錄於物件頭,儲存物件的hashcode或鎖資訊

這裡補充無鎖狀態的Mark Word狀態

鎖狀態 hashcode 分代年齡 是否偏向鎖 鎖標誌位
無鎖狀態 物件的hashcode 物件分代年齡 0 01

偏向鎖狀態的Mark Word狀態

鎖狀態 Thread ID epoch 分代年齡 是否偏向鎖 鎖標誌位
偏向鎖 記錄指向的執行緒id epoch 物件分代年齡 1 01

加鎖與解鎖

biasedlock

輕量級鎖

內容

輕量級鎖是通過自旋實現非阻塞同步,屬於樂觀鎖,可以膨脹為重量級鎖

Mark Word狀態

鎖狀態 記錄 鎖標誌位
輕量級鎖 指向棧中鎖記錄的指標 00

加鎖與解鎖

加鎖

lightlock

解鎖

lightunlock

重量級鎖

內容

鎖升級為重量級鎖後,其他試圖獲取鎖的執行緒均會被阻塞,等待持有鎖的執行緒釋放鎖後,被喚醒的執行緒會開始競爭獲取鎖。

重量級鎖是一種互斥鎖,其依賴於物件內部的monitor鎖實現,在作業系統層面是通過MutexLock實現的。雖然在阻塞時不需要耗費CPU資源,但是執行緒從阻塞狀態喚醒需要作業系統完成狀態轉換(使用者態到核心態),耗時較長。

Mark Word狀態

鎖狀態 記錄 鎖標誌位
重量級鎖 指向互斥量(重量級鎖)的指標 10

比較

對比表參考《Java併發程式設計的藝術》

優點 缺點 適用場景
偏向鎖 加鎖和解鎖不需要額外的消耗,和執行非同步方法相比僅存在納秒級的差距 如果執行緒間存在鎖競爭,會帶來額外的鎖撤銷的消耗 適用於只有一個執行緒訪問同步塊的場景
輕量級鎖 非阻塞同步,提高程式響應速度 自旋消耗CPU資源 追求響應時間,同步方法執行速度較快
重量級鎖 執行緒阻塞時不需要消耗CPU 執行緒阻塞,響應時間緩慢 追求吞吐量,同步塊執行時間較長

參考文章

  1. 《Java併發程式設計的藝術》2.2 synchronized的實現原理與應用
  2. 執行緒安全(上)--徹底搞懂synchronized(從偏向鎖到重量級鎖)
  3. Java併發程式設計:Synchronized底層優化(偏向鎖、輕量級鎖)

如有問題,還請指出

相關文章