2012-03-31 129 views
7

以下Java代碼會生成以下JVM字節碼。同步塊中的意外代碼

我很好奇爲什麼生成從偏移量31到偏移量36的代碼。 JLS7或JVM7規範中沒有提到這一點。我錯過了什麼嗎?

即使我刪除println語句,由於println調用已被刪除,代碼(偏移31到偏移量36)仍然會生成,只能在較早的位置生成。

// 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 

回答

2

我不知道它是在JLS,但必須某處說,當一個異常被拋出,鎖被釋放。您可以使用Unsafe.monitor進行此操作。輸入/退出

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"); 
} 

我相信您最後可能會漏掉一個catch塊表。

+0

你好,彼得,你的回答並沒有回答這個問題:「我很好奇爲什麼代碼......是生成的」,甚至「我錯過了什麼?」。儘管感謝您的參與。 – chuacw 2012-04-01 00:33:51

+0

代碼生成是因爲必須有代碼才能釋放鎖,請參閱我的示例。你錯過了我的解釋嘗試。 ;) – 2012-04-01 07:44:24

+0

雷內的解釋比較好。另外請注意,我沒有要求其他方法。不管怎麼說,還是要謝謝你。 – chuacw 2012-04-02 00:58:27

7

編譯器在此處添加一個不可見的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 specs

通常情況下,Java編程語言的編譯器可以確保通過實施 鎖定操作執行之前,在執行同步語句的主體之前執行的監視器指令是 ,每當同步語句完成時,通過由monitorexit 指令實現的解鎖操作進行匹配,無論是 完成是正常的或突然的。

+0

你好雷內,謝謝。 – chuacw 2012-03-31 16:37:01

+0

不客氣;-)。 – Neet 2012-03-31 16:51:17