2012-03-31 9 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.monitorEnterでこれを行うことができます/終了し、私はあなたが欠落している可能性があり最後のcatchブロックのテーブルがあると信じて

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

+0

こんにちはPeterさんの答えは、「コードがなぜ生成されたのか不思議です。しかし、あなたの参加に感謝します。 – chuacw

+0

ロックを解除するコードが必要なのでコードが生成されます。私の例を参照してください。あなたは私の説明しようとしなかった。 ;) –

+0

ルネの説明が良いです。また、私は別の方法を求めなかったことに注意してください。とにかくありがとう。 – chuacw

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プログラミング言語のコンパイラは、ロック操作がで実装 ことを保証します。通常、 synchronized文の本体の実行前に実行されたmonitreter命令は であり、synchronized文が完了するたびにmonitorexit 命令によって実装されたロック解除操作と一致します完了は正常または突然です。

+0

こんにちは、レネ、ありがとう。 – chuacw

+0

あなたを歓迎します;-)。 – Neet