Java synchronized:底層原理與鎖升級機制詳解
synchronized是java多線程編程中常用的同步機制,其底層實現和鎖升級過程一直備受關注。本文通過代碼示例,深入剖析synchronized的底層原理以及鎖的升級路徑:無鎖、偏向鎖、輕量級鎖和重量級鎖。
代碼示例與運行結果分析
以下Java代碼演示了synchronized鎖的升級過程:
public static void main(String[] args) throws InterruptedException { Thread.sleep(5000); Object obj = new Object(); System.out.println("初始狀態 =====================" + "n" + ClassLayout.parseInstance(obj).toPrintable()); new Thread(() -> { synchronized (obj) { System.out.println(Thread.currentThread().getName() + "獲取鎖執行中。。。n" + ClassLayout.parseInstance(obj).toPrintable()); } }, "Thread-A").start(); Thread.sleep(1000); new Thread(() -> { synchronized (obj) { System.out.println(Thread.currentThread().getName() + "獲取鎖執行中。。。n" + ClassLayout.parseInstance(obj).toPrintable()); } }, "Thread-B").start(); Thread.sleep(5000); System.out.println(Thread.currentThread().getName() + ClassLayout.parseInstance(obj).toPrintable()); }
運行結果(可能因jvm版本而異): 結果將顯示對象頭Mark word在不同線程訪問時的狀態變化,展示了鎖的升級過程。 由于偏向鎖在現代JVM中通常默認關閉,你可能觀察到直接從無鎖狀態升級到輕量級鎖的狀態變化。
synchronized底層機制與鎖升級
synchronized基于HotSpot虛擬機中的監視器鎖(Monitor)實現,依賴對象頭中的Mark Word和操作系統互斥鎖(Mutex Lock)。Mark Word存儲對象的運行時數據,包括鎖狀態。
1. 無鎖狀態: 對象初始狀態,Mark Word存儲哈希碼等信息。
2. 偏向鎖狀態: 只有一個線程訪問同步塊時,JVM會進行偏向鎖優化,Mark Word記錄線程ID。 這減少了不必要的CAS操作,提升性能。 (現代JVM中通常默認關閉)
3. 輕量級鎖狀態: 當第二個線程嘗試獲取鎖時,如果已存在偏向鎖(或偏向鎖已失效),則升級為輕量級鎖。 線程在棧幀中創建鎖記錄,使用CAS操作嘗試將Mark Word替換為指向鎖記錄的指針。成功則獲取鎖,失敗則升級為重量級鎖。
4. 重量級鎖狀態: 輕量級鎖競爭失敗(CAS操作失敗),鎖升級為重量級鎖。 線程阻塞,依賴操作系統Mutex Lock實現同步,性能開銷較大。
結果分析與總結
代碼示例中,鎖狀態會經歷不同的階段,這體現了synchronized的鎖升級機制。 需要注意的是,由于JVM優化策略,偏向鎖可能被禁用,直接從無鎖狀態升級到輕量級鎖。 理解synchronized的鎖升級機制,有助于開發者更有效地利用這一同步工具,并根據實際情況選擇合適的鎖策略。 現代JVM的優化策略使得synchronized在許多情況下具有較高的性能。