以下Java代码生成以下JVM字节码.
我很好奇为什么生成从偏移31到偏移36的代码.JLS7或JVM7规范中没有任何内容涉及此问题.我错过了什么吗?
即使我删除了println语句,代码(偏移31到偏移36)仍然只在较早的位置生成,因为println调用已被删除.
// Java code
void testMonitor() {
Boolean x = new Boolean(false);
synchronized(x) {
System.out.println("inside synchronized");
System.out.println("blah");
};
System.out.println("done");
}
// JVM bytecode
Offset Instruction Comments (Method: testMonitor)
0 new 42 (java.lang.Boolean)
3 dup
4 iconst_0
5 invokespecial 44 (java.lang.Boolean.<init>)
8 astore_1 (java.lang.Boolean x)
9 aload_1 (java.lang.Boolean x)
10 dup
11 astore_2
12 monitorenter
13 getstatic 15 (java.lang.System.out)
16 ldc 47 (inside synchronized)
18 invokevirtual 23 (java.io.PrintStream.println)
21 getstatic 15 (java.lang.System.out)
24 ldc 49 (blah)
26 invokevirtual 23 (java.io.PrintStream.println)
29 aload_2
30 monitorexit
31 goto 37
34 aload_2
35 monitorexit
36 athrow
37 getstatic 15 (java.lang.System.out)
40 ldc 51 (done)
42 invokevirtual 23 (java.io.PrintStream.println)
45 return
Run Code Online (Sandbox Code Playgroud)
编译器在此处添加了一个不可见的try/catch块,以确保释放监视器状态(这在VM规范中有记录,请参见帖子底部).您可以使用javap -v并查看异常表来验证这一点:
void testMonitor();
Code:
Stack=3, Locals=3, Args_size=1
0: new #15; //class java/lang/Boolean
3: dup
4: iconst_0
5: invokespecial #17; //Method java/lang/Boolean."<init>":(Z)V
8: astore_1
9: aload_1
10: dup
11: astore_2
12: monitorenter
13: getstatic #20; //Field java/lang/System.out:Ljava/io/PrintStream;
16: ldc #26; //String inside synchronized
18: invokevirtual #28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
21: getstatic #20; //Field java/lang/System.out:Ljava/io/PrintStream;
24: ldc #34; //String blah
26: invokevirtual #28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
29: aload_2
30: monitorexit
31: goto 37
34: aload_2
35: monitorexit
36: athrow
37: getstatic #20; //Field java/lang/System.out:Ljava/io/PrintStream;
40: ldc #36; //String done
42: invokevirtual #28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
45: return
Exception table:
from to target type
13 31 34 any
34 36 34 any
Run Code Online (Sandbox Code Playgroud)
编辑:从JVM规范:
通常,Java编程语言的编译器确保在执行synchronized语句主体之前执行的monitorenter指令实现的锁定操作与每当synchronized语句完成时由monitorexit指令实现的解锁操作匹配,无论是否完成是正常的还是突然的
我不知道它在 JLS 中的什么地方,但它必须在某个地方说,当抛出异常时,会释放锁。您可以使用 Unsafe.monitorEnter/Exit 来执行此操作
void testMonitor() {
Boolean x = new Boolean(false);
theUnsafe.monitorEnter(x);
try {
System.out.println("inside synchronized");
System.out.println("blah");
} catch(Throwable t) {
theUnsafe.monitorExit(x);
throw t;
};
theUnsafe.monitorExit(x);
System.out.println("done");
}
Run Code Online (Sandbox Code Playgroud)
我相信最后您可能会丢失一个 catch 块表。
| 归档时间: |
|
| 查看次数: |
431 次 |
| 最近记录: |