try/finally セクションを持つ関数があり、それを実行しているスレッドが try ブロック内で中断された場合、実際に中断が発生する前に finally ブロックが実行されますか?
6 に答える
Java チュートリアル によるとtry
、「またはcatch
コードを実行しているスレッドが中断または強制終了されたfinally
場合、アプリケーション全体は続行されますが、ブロックは実行されない可能性があります。」
全文は次のとおりです。
finally
ブロックは、ブロックが終了するときに常に実行されます。try
これによりfinally
、予期しない例外が発生した場合でもブロックが実行されます。しかし、これは例外処理だけでなく、プログラマーが、、またはfinally
によって誤ってクリーンアップ コードをバイパスすることを回避するのにも役立ちます。クリーンアップ コードをブロックに入れることは、例外が予想されない場合でも、常に良い方法です。return
continue
break
finally
注:
try
またはcatch
コードの実行中に JVM が終了すると、finally
ブロックが実行されない場合があります。同様に、try
またはcatch
コードを実行しているスレッドが中断または強制終了されたfinally
場合、アプリケーション全体は続行されますが、ブロックは実行されない可能性があります。
class Thread1 implements Runnable {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("finally executed");
}
}
}
...
t1.start();
t1.interrupt();
印刷されます-最終的に実行されました
Javaのスレッド割り込みは、フラグを設定しているだけです。現在実行中のコードに特別なことが発生したり、制御の流れに影響を与えたりすることはありません。
スレッドがInterruptedExceptionをスローする操作に関与している、または入力しようとすると、そのメソッドが呼び出されたポイントから例外がスローされ、tryブロック内にある場合は、例外が通常どおり終了する前にfinallyが実行されます。 。
answerへのコメントで、@Risadinha は、を呼び出してブロック内の中断フラグを復元した場合、ブロック内のコードが実行されるかどうかについて非常に有効な質問をしました。finally
catch
Thread.currentThread().interrupt()
テストする小さなコード スニペットを次に示します。
final SomeContext context = new SomeContext();
Thread thread = new Thread() {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
// this code gets executed even though
// we interrupt thread in catch block.
context.value = 9;
}
}
};
thread.start();
thread.interrupt();
thread.join(); // need to wait for thread code to complete
assertEquals(context.value, 9); // values are the same!
SomeContext クラスのコード:
class SomeContext {
public volatile int value = 10;
}
Oracle の Java チュートリアルの多くは役に立ちますが (保護されたブロックのページと SAX の紹介を参照する回答があります)、それらは必ずしも信頼できるものではなく、中には間違いや不完全なものもあります。質問で参照されている引用は、混乱を招くJVMの終了と中断を混同しています。
まず、Java のスレッド割り込みは、OS レベルの割り込みとは何の関係もありません。名前を共有すると混乱が生じる可能性がありますが、つながりはありません。
次に、JVM の終了は明らかに、クリーンアップを行う機会なしにスレッドを強制終了します。スレッドが finally ブロックに到達する前にプロセスが終了した場合は、残念です。しかし、中断とは比較になりません。中断については、finally ブロックの完了を妨げるものは何もありません。
割り込みの設計原則は、割り込みに基づいて動作するには、割り込みを受けるスレッドの協力が必要であるというものです。中断されたスレッドは、その裁量で応答します。中断によってスレッドが強制的に実行されることはありません。Thread#interrupt() を呼び出すと、スレッドにフラグが設定されます。待機やスリープなどのブロッキング メソッドは、フラグをチェックして、早期に起動する必要があるかどうかを確認します。(InterruptedException はチェック例外であるため、誰がいつスローしたかを知ることができ、Runnable はそれを計画できます。) また、任意のコードで Thread#isInterrupted() を使用して、そのスレッドにフラグが設定されているかどうかを確認できます。
Thread#sleep() は、割り込みフラグが設定されていることを認識すると、割り込み例外をスローする前にフラグをクリアします。スレッドが InterruptedException をキャッチした場合、そのスレッドで割り込みについて知る必要がある他のコードが実行されている場合に備えて、Thread.currentThread().interrupt() を使用してフラグを復元することをお勧めします。これは、ネストされたシンクロナイザーでより複雑な状況が発生した場合に役立ちます。たとえば、深くネストされたコンポーネントのスリープが中断され、クリアされたままにしておくと、上位レイヤーが中断を認識できなくなる可能性があります。ここでの他の回答のような単純なおもちゃの例では、フラグが復元されたかどうかは関係ありません。何もチェックされず、スレッドは終了します。
割り込みの効果はInterruptedException
、次にブロッキング操作が発生したときに をスローすることです (実際には、 をスローできることを指定するメソッドが次に呼び出されたときInterruptedException
)。その時点で、通常どおり、通常のtry/catch
実行フローに従います。これは実際に、および該当するesfinally
の後にブロックを実行します。try
catch
中断前ではなく、try ブロックからの他の例外と同じように実行されます。