4

Java に似た言語用に独自のコンパイラを作成していますが、コンパイルに問題がありsynchronized blocksます。try-finallyそれらをブロックに単純化するために、次のアイデアを思いつきました。

synchonized (obj) {
     statements...
}

と交換可能

Object _lock = obj
_monitorEnter(lock)
try {
    statements...
}
finally {
    _monitorExit(lock)
}

および は、および命令_monitorEnter_monitorExit表します。MONITORENTERMONITOREXIT

synchronizedがどのようにコンパイルされるかというこの仮定は正しいですか、それとも何か不足していますか?

編集

以前の実装では、ボディ内のreturnandthrowステートメントに対していくつかの特別な処理が行われていました。基本的に、すべてのlock変数とMONITOREXITそれらを各*RETURNorTHROW命令の前に手動でロードします。これはブロックによって処理されfinallyますか、それともこれらのチェックが必要ですか?

4

2 に答える 2

5

あなたの仮定は正しいです。synchronizedJava 言語のブロックは、monitorenterおよびmonitorexit命令で実装されます。JVM 仕様の詳細は、こちらで確認できます。

Java 仮想マシンでの同期は、モニターの開始と終了によって、明示的に (monitorenter と monitorexit 命令を使用して)、または暗黙的に (メソッド呼び出しと return 命令で) 実装されます。

コンパイラは、本体内でスローされたすべての例外を処理するバイトコードを生成するsynchronizedため、try-finally アプローチはここでうまく機能します。

ステートメントの指定finally、モニターの解放について何も伝えません。synchronized最初のリンクで提供されている例は、ブロックにラップされた単純なメソッドのバイトコードを示しています。ご覧のとおり、monitorexit 命令の実行を保証するために、考えられるすべての例外が処理されます。コンパイラに同じ動作を実装する必要があります (finally ステートメント内でモニターを解放するコードを記述します)。

void onlyMe(Foo f) {
    synchronized(f) {
        doSomething();
    }
}

Method void onlyMe(Foo)
0   aload_1             // Push f
1   dup                 // Duplicate it on the stack
2   astore_2            // Store duplicate in local variable 2
3   monitorenter        // Enter the monitor associated with f
4   aload_0             // Holding the monitor, pass this and...
5   invokevirtual #5    // ...call Example.doSomething()V
8   aload_2             // Push local variable 2 (f)
9   monitorexit         // Exit the monitor associated with f
10  goto 18             // Complete the method normally
13  astore_3            // In case of any throw, end up here
14  aload_2             // Push local variable 2 (f)
15  monitorexit         // Be sure to exit the monitor!
16  aload_3             // Push thrown value...
17  athrow              // ...and rethrow value to the invoker
18  return              // Return in the normal case
Exception table:
From    To      Target      Type
4       10      13          any
13      16      13          any
于 2016-01-23T13:14:45.347 に答える
0

ご想像のとおり、Java コンパイラは同期ブロックを try-finally によく似たものにコンパイルします。ただし、小さな違いが 1 つあります。例外処理は、によってスローされた例外をキャッチmonitorexitし、ロックを解放しようとして無限にループします。Java では、このように制御フローを指定する方法はありません。

于 2016-01-23T15:09:24.777 に答える