[英]Unexpected code in synchronized block
以下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
编译器在此处添加了一个不可见的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
编辑:从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");
}
我相信最后你可能会遇到一个阻塞表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.