以 32 位虛擬機器為例
普通物件
|--------------------------------------------------------------|
| Object Header (64 bits) |
|------------------------------------|-------------------------|
| Mark Word (32 bits) | klass Word (32 bits) |
|------------------------------------|-------------------------|
陣列物件
|---------------------------------------------------------------------------------|
| Object Header (96 bits) |
|--------------------------------|-----------------------|------------------------|
| Mark Word(32bits) | Klass Word(32bits) | array length(32bits) |
|--------------------------------|-----------------------|------------------------|
其中 Mark Word 結構為
|-------------------------------------------------------|--------------------|
| Mark Word (32 bits) | State |
|-------------------------------------------------------|--------------------|
| hashcode:25 | age:4 | biased_lock:0 | 01 | Normal |
|-------------------------------------------------------|--------------------|
| thread:23 | epoch:2 | age:4 | biased_lock:1 | 01 | Biased |
|-------------------------------------------------------|--------------------|
| ptr_to_lock_record:30 | 00 | Lightweight Locked |
|-------------------------------------------------------|--------------------|
| ptr_to_heavyweight_monitor:30 | 10 | Heavyweight Locked |
|-------------------------------------------------------|--------------------|
| | 11 | Marked for GC |
|-------------------------------------------------------|--------------------|
64 位虛擬機器 Mark Word
|--------------------------------------------------------------------|--------------------|
| Mark Word (64 bits) | State |
|--------------------------------------------------------------------|--------------------|
| unused:25 | hashcode:31 | unused:1 | age:4 | biased_lock:0 | 01 | Normal |
|--------------------------------------------------------------------|--------------------|
| thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | 01 | Biased |
|--------------------------------------------------------------------|--------------------|
| ptr_to_lock_record:62 | 00 | Lightweight Locked |
|--------------------------------------------------------------------|--------------------|
| ptr_to_heavyweight_monitor:62 | 10 | Heavyweight Locked |
|--------------------------------------------------------------------|--------------------|
| | 11 | Marked for GC |
|--------------------------------------------------------------------|--------------------|
參考資料
2、Monitor 原理
Monitor 被翻譯為監視器或管程
每個 Java 物件都可以關聯一個 Monitor 物件,如果使用 synchronized 給物件上鎖(重量級)之後,該物件頭的 Mark Word 中就被設定指向 Monitor 物件的指標
Monitor 結構如下
-
剛開始 Monitor 中 Owner 為 null
-
當 Thread-2 執行 synchronized(obj) 就會將 Monitor 的所有者 Owner 置為 Thread-2,Monitor中只能有一個 Owner
-
在 Thread-2 上鎖的過程中,如果 Thread-3,Thread-4,Thread-5 也來執行 synchronized(obj),就會進入 EntryList BLOCKED
-
Thread-2 執行完同步程式碼塊的內容,然後喚醒 EntryList(阻塞佇列) 中等待的執行緒來競爭鎖,競爭是非公平的
-
圖中 WaitSet 中的 Thread-0,Thread-1 是之前獲得過鎖,但條件不滿足進入 WAITING 狀態的執行緒,後面講 wait-notify 時會分析
注意:
synchronized 必須是進入同一個物件的 monitor 才有上述的效果
不加 synchronized 的物件不會關聯監視器,不遵從以上規則
3、synchronized 原理
static final Object lock = new Object();
static int counter = 0;
public static void main(String[] args) {
synchronized (lock) {
counter++;
}
}
對應的位元組碼為
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: getstatic #2 // <- lock引用 (synchronized開始)
3: dup // 複製一份引用
4: astore_1 // lock引用 -> slot 1
5: monitorenter // 將 lock物件 MarkWord 置為 Monitor 指標
6: getstatic #3 // <- i
9: iconst_1 // 準備常數 1
10: iadd // +1
11: putstatic #3 // -> i
14: aload_1 // <- lock引用
15: monitorexit // 將 lock物件 MarkWord 重置, 喚醒 EntryList
16: goto 24 // 19-23 為異常處理
19: astore_2 // e -> slot 2
20: aload_1 // <- lock引用
21: monitorexit // 將 lock物件 MarkWord 重置, 喚醒 EntryList
22: aload_2 // <- slot 2 (e)
23: athrow // throw e
24: return
Exception table: // 異常檢測
from to target type
6 16 19 any // 6-16 行出現異常 目標為19行
19 22 19 any // 19-22 行出現異常 目標為19行
LineNumberTable:
line 8: 0
line 9: 6
line 10: 14
line 11: 24
LocalVariableTable:
Start Length Slot Name Signature
0 25 0 args [Ljava/lang/String;
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 19
locals = [ class "[Ljava/lang/String;", class java/lang/Object ]
stack = [ class java/lang/Throwable ]
frame_type = 250 /* chop */
offset_delta = 4
注意
方法級別的 synchronized 不會在位元組碼指令中有所體現