这是写了一个小Demo
public class DemoSynchronized {
private final static Object LOCK = new Object();
public static void main(String[] args) {
Runnable thread = ()->{
synchronized (LOCK){
try {
Thread.sleep(200_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t1 = new Thread(thread);
Thread t2 = new Thread(thread);
Thread t3 = new Thread(thread);
t1.start();
t2.start();
t3.start();
}
}
通过反汇编查看发现,竟然有两个monitorexit指令
这是上面这段代码完整反汇编
Compiled from "DemoSynchronized.java"
public class thread.DemoSynchronized {
private static final java.lang.Object LOCK;
public thread.DemoSynchronized();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
5: astore_1
6: new #3 // class java/lang/Thread
9: dup
10: aload_1
11: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
14: astore_2
15: new #3 // class java/lang/Thread
18: dup
19: aload_1
20: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
23: astore_3
24: new #3 // class java/lang/Thread
27: dup
28: aload_1
29: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
32: astore 4
34: aload_2
35: invokevirtual #5 // Method java/lang/Thread.start:()V
38: aload_3
39: invokevirtual #5 // Method java/lang/Thread.start:()V
42: aload 4
44: invokevirtual #5 // Method java/lang/Thread.start:()V
47: return
private static void lambda$main$0();
Code:
0: getstatic #6 // Field LOCK:Ljava/lang/Object;
3: dup
4: astore_0
5: monitorenter
6: ldc2_w #7 // long 200000l
9: invokestatic #9 // Method java/lang/Thread.sleep:(J)V
12: goto 20
15: astore_1
16: aload_1
17: invokevirtual #11 // Method java/lang/InterruptedException.printStackTrace:()V
20: aload_0
21: monitorexit
22: goto 30
25: astore_2
26: aload_0
27: monitorexit
28: aload_2
29: athrow
30: return
Exception table:
from to target type
6 12 15 Class java/lang/InterruptedException
6 22 25 any
25 28 25 any
static {};
Code:
0: new #12 // class java/lang/Object
3: dup
4: invokespecial #1 // Method java/lang/Object."<init>":()V
7: putstatic #6 // Field LOCK:Ljava/lang/Object;
10: return
}
看一下反汇编代码中的这一段,第5行、21行、27行,会有两个monitorexit指令
private static void lambda$main$0();
Code:
0: getstatic #6 // Field LOCK:Ljava/lang/Object;
3: dup
4: astore_0
5: monitorenter
6: ldc2_w #7 // long 200000l
9: invokestatic #9 // Method java/lang/Thread.sleep:(J)V
12: goto 20
15: astore_1
16: aload_1
17: invokevirtual #11 // Method java/lang/InterruptedException.printStackTrace:()V
20: aload_0
21: monitorexit
22: goto 30
25: astore_2
26: aload_0
27: monitorexit
28: aload_2
29: athrow
30: return
通过查看资料得知,第一个monitorexit指令是同步代码块正常释放锁的一个标志;
如果同步代码块中出现Exception或者Error,则会调用第二个monitorexit指令来保证释放锁