java 中synchronized 鎖的優化都是依賴對象頭實現的,網上有關於對象頭的資料大致概況如下圖:
對象頭信息是實現synchronized 優化的基礎;
主要思想就是通過代碼層面的判斷,來減少真正鎖的獲取與釋放時,CPU 用戶態/內核態的切換帶來的高成本(根本原因是java中的每個線程都映射到內核中一個線程,阻塞與喚醒都需要工作空間的切換);
自旋鎖與偏向鎖都適用於實際應用中,可能只有單個線程在使用鎖的情況;
輕量級鎖適用於同步塊占用時間很短的多線程競爭場景;
自旋鎖、偏向鎖、輕量級鎖都是通過自旋的方式來獲取鎖;
自旋鎖:
獲取鎖時,增加獲取次數的設置;
自適應的自旋鎖(1.6)會根據之前自旋的情況來判斷下次自旋的次數;如果之前自旋成功概率較高,那么就增加下一次的自旋次數,否則減少自旋次數;
偏向鎖:
大概意思就是如果某個線程獲取鎖成功,下次就更偏向於該線程獲得鎖;
條件:
鎖對象的對象頭-鎖標志位為01
線程A在獲取鎖時,
1、查看鎖對象的對象頭線程ID是否為當前線程A,如果是,則獲取鎖成功;
2、否則CAS自旋替換線程ID,如果替換成功則獲取成功;
3、更新失敗則升級鎖類型為輕量級鎖;
輕量級鎖:
在線程棧幀中創建一個Lock record,用於保存鎖對象的對象頭信息;鎖對象頭中保存一個當前持有輕量級鎖的線程的棧幀Lock record的指針;
條件:
鎖對象的對象頭-鎖標志位為00
線程A在獲取鎖時,
1、比較線程A的棧幀中Lock record 與 鎖對象頭的棧幀指針是否一致;如果一致則獲取成功;
2、否則CAS自旋更改鎖對象頭的棧幀指針為當前線程A的棧幀Lock record地址,如果替換成功則獲取輕量級鎖成功;
3、更新失敗則升級為重量級鎖;
重量級鎖:
重量級鎖依賴於操作系統的Mutex Lock,需要操作系統對線程狀態的切換;目前JVM的線程切換需要操作系統切換用戶態到核心態,成本較高,所以叫重量級鎖;