Synchronized
是Java中最常用的內置鎖機制,用于確保多線程環境下的同步。其底層原理涉及到JVM(Java虛擬機)和字節碼指令。以下是 synchronized
的底層工作原理的詳細介紹:
1. 基本概念
- 對象頭(Object Header):每個Java對象在內存中都有一個對象頭,包含了鎖標志位(Lock Word)。
- Monitor:每個對象都有一個與之關聯的監視器(Monitor),監視器是由C++實現的對象,它主要用于實現對象的同步機制。
2. 鎖的狀態
鎖的狀態在對象頭中的鎖標志位表示,可以有以下幾種狀態:
- 無鎖(Unlocked):沒有線程持有鎖。
- 偏向鎖(Biased Lock):當一個線程第一次訪問一個對象時,對象頭中的鎖標志位會變為偏向鎖,表明該線程持有鎖。
- 輕量級鎖(Lightweight Lock):當第二個線程嘗試獲取鎖時,偏向鎖會升級為輕量級鎖。
- 重量級鎖(Heavyweight Lock):當輕量級鎖競爭失敗時,會升級為重量級鎖。重量級鎖會阻塞所有嘗試獲取鎖的線程,直到持有鎖的線程釋放鎖。
3. synchronized 的實現
synchronized
關鍵字可以用于方法或代碼塊中。其底層實現如下:
3.1 同步代碼塊
synchronized (this) {// critical section
}
同步代碼塊的實現依賴于字節碼指令 monitorenter
和 monitorexit
:
- monitorenter:當線程進入同步代碼塊時執行,嘗試獲取對象的Monitor鎖。
- monitorexit:當線程退出同步代碼塊時執行,釋放對象的Monitor鎖。
每個Monitor對象都包含一個計數器(Owner Count)和一個指向持有該鎖的線程的指針(Owner)。
3.2 同步方法
public synchronized void method() {// critical section
}
同步方法使用 ACC_SYNCHRONIZED
標志。當方法調用時,JVM會自動獲取對象的Monitor鎖,方法執行完畢后釋放鎖。
4. 鎖的升級與膨脹
- 偏向鎖:偏向鎖會在無競爭的情況下將鎖偏向第一個獲取它的線程。當同一個線程再次進入同步塊時,不需要進行同步操作。
- 輕量級鎖:當第二個線程嘗試獲取偏向鎖時,會觸發偏向鎖升級為輕量級鎖。這時會在當前線程棧幀中創建一個鎖記錄(Lock Record),并將對象頭中的鎖標志位指向這個鎖記錄。
- 重量級鎖:如果鎖競爭激烈,輕量級鎖會升級為重量級鎖,涉及到操作系統的互斥量(mutex)實現。重量級鎖會導致線程阻塞和上下文切換。
5. 底層實現示例
以下是一個簡單的示例,展示了同步代碼塊和同步方法在字節碼層面的實現:
同步代碼塊
public void syncBlock() {synchronized (this) {System.out.println("Inside synchronized block");}
}
編譯后的字節碼:
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: ldc #3 // String Inside synchronized block
9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
12: aload_1
13: monitorexit
14: goto 22
17: astore_2
18: aload_1
19: monitorexit
20: aload_2
21: athrow
22: return
同步方法
public synchronized void syncMethod() {System.out.println("Inside synchronized method");
}
編譯后的字節碼:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Inside synchronized method
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
總結
Synchronized
通過對象頭中的鎖標志位和Monitor對象實現了多線程的同步機制。通過鎖的升級與膨脹策略,它在無競爭的情況下盡可能減少同步開銷,而在競爭激烈的情況下保證線程安全。理解其底層原理有助于更好地使用 synchronized
,從而編寫出高效的并發程序。