Synchronized 底層實現
Synchronized 底層實現涉及到鎖升級的概念。由偏向鎖,升級為輕量鎖(自旋鎖/適應性自旋鎖),再升級為重量級鎖。
Synchronized 的底層實現與用的是什麼版本的 HotSpot 有關,這裡以 OpenJdk 1.8 為例。
偏向鎖
如果當前 Synchronized 修飾的程式碼,只有一個執行緒去訪問,那此時執行緒去加鎖/釋放鎖,顯然時沒有必要,這隻會造成資源浪費。於是引入了偏向鎖。
在 Synchronized 加鎖的物件的物件頭,MarnWord 記錄下當前執行緒的 ID,持有偏向鎖的執行緒,每次進入鎖相關同步程式碼塊時,只需要比對一下,MarnWord 記錄的執行緒是否為本執行緒,如果是執行緒則獲取鎖成功。這就是偏向鎖,偏向記錄執行緒 ID 的鎖。
當執行緒訪問同步塊並獲取鎖時處理流程如下:
- 檢查 mark word 的執行緒 id 。
- 如果為空則設定 CAS 替換當前執行緒 id。如果替換成功則獲取鎖成功,如果失敗則撤銷偏向鎖。
- 如果不為空則檢查 執行緒 id為是否為本執行緒。如果是則獲取鎖成功,如果失敗則撤銷偏向鎖。
如果發生執行緒競爭,2、3失敗的情況,那麼,會升級為輕量鎖(自旋鎖)。
輕量鎖
輕量鎖指的時鎖的狀態,而自旋是一種獲取鎖的機制。自旋是為了讓當前執行緒“稍等一下”,適用於同步程式碼塊執行時間短的情況。
自旋鎖
當執行緒無法獲取鎖時,該執行緒進入迴圈等待(自旋),此時該執行緒狀態不是阻塞的,也就無需耗費資源去喚醒執行緒。預設情況下,固定 10 次自旋次數,可以使用引數 -XX : PreBlockSpin
適應性自旋鎖
在 JDK1.6 引入了適應性自旋鎖,自旋次數不在固定,而是由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態來決定。如果對於某個鎖很少自旋成功那麼以後有可能省略掉自旋過程以避免資源浪費。
如果執行緒始終無法獲取到鎖,那麼會升級為重量級鎖。
重量級鎖
重量級鎖是將除了擁有鎖的執行緒以外的執行緒都阻塞。
進入到重量鎖,涉及到作業系統排程,會產生額外的開銷。這部分內容涉及到作業系統方面的知識,我不是很懂,暫且忽略。
總結
- 偏向鎖通過對比 Mark Word thread id 解決加鎖問題。
- 輕量級鎖是通過用 CAS 操作 Mark Word 和自旋來解決加鎖問題,避免執行緒阻塞和喚醒而影響效能。
- 重量級鎖是將除了擁有鎖的執行緒以外的執行緒都阻塞。
參考連結:
鎖升級概念:沒錯,我就是廁所所長!(一)
鎖升級概念:沒錯,我就是廁所所長!(二)
synchronized 實現原理