23

try/finally セクションを持つ関数があり、それを実行しているスレッドが try ブロック内で中断された場合、実際に中断が発生する前に finally ブロックが実行されますか?

4

6 に答える 6

12

Java チュートリアル によるとtry、「またはcatchコードを実行しているスレッドが中断または強制終了されたfinally場合、アプリケーション全体は続行されますが、ブロックは実行されない可能性があります。」

全文は次のとおりです。

finallyブロックは、ブロックが終了するときに常に実行されます。tryこれによりfinally、予期しない例外が発生した場合でもブロックが実行されます。しかし、これは例外処理だけでなく、プログラマーが、、またはfinallyによって誤ってクリーンアップ コードをバイパスすることを回避するのにも役立ちます。クリーンアップ コードをブロックに入れることは、例外が予想されない場合でも、常に良い方法です。returncontinuebreakfinally

注: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();

印刷されます-最終的に実行されました

于 2013-01-29T06:18:21.503 に答える
4

Javaのスレッド割り込みは、フラグを設定しているだけです。現在実行中のコードに特別なことが発生したり、制御の流れに影響を与えたりすることはありません。

スレッドがInterruptedExceptionをスローする操作に関与している、または入力しようとすると、そのメソッドが呼び出されたポイントから例外がスローされ、tryブロック内にある場合は、例外が通常どおり終了する前にfinallyが実行されます。 。

于 2013-01-29T06:22:20.947 に答える
4

answerへのコメントで、@Risadinha は、を呼び出してブロック内の中断フラグを復元した場合、ブロック内のコードが実行されるかどうかについて非常に有効な質問をしました。finallycatchThread.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;
}
于 2015-10-30T12:51:43.093 に答える
4

Oracle の Java チュートリアルの多くは役に立ちますが (保護されたブロックのページと SAX の紹介を参照する回答があります)、それらは必ずしも信頼できるものではなく、中には間違いや不完全なものもあります。質問で参照されている引用は、混乱を招くJVMの終了と中断を混同しています。

まず、Java のスレッド割り込みは、OS レベルの割り込みとは何の関係もありません。名前を共有すると混乱が生じる可能性がありますが、つながりはありません

次に、JVM の終了は明らかに、クリーンアップを行う機会なしにスレッドを強制終了します。スレッドが finally ブロックに到達する前にプロセスが終了した場合は、残念です。しかし、中断とは比較になりません。中断については、finally ブロックの完了を妨げるものは何もありません。

割り込みの設計原則は、割り込みに基づいて動作するには、割り込みを受けるスレッドの協力が必要であるというものです。中断されたスレッドは、その裁量で応答します。中断によってスレッドが強制的に実行されることはありません。Thread#interrupt() を呼び出すと、スレッドにフラグが設定されます。待機やスリープなどのブロッキング メソッドは、フラグをチェックして、早期に起動する必要があるかどうかを確認します。(InterruptedException はチェック例外であるため、誰がいつスローしたかを知ることができ、Runnable はそれを計画できます。) また、任意のコードで Thread#isInterrupted() を使用して、そのスレッドにフラグが設定されているかどうかを確認できます。

Thread#sleep() は、割り込みフラグが設定されていることを認識すると、割り込み例外をスローする前にフラグをクリアします。スレッドが InterruptedException をキャッチした場合、そのスレッドで割り込みについて知る必要がある他のコードが実行されている場合に備えて、Thread.currentThread().interrupt() を使用してフラグを復元することをお勧めします。これは、ネストされたシンクロナイザーでより複雑な状況が発生した場合に役立ちます。たとえば、深くネストされたコンポーネントのスリープが中断され、クリアされたままにしておくと、上位レイヤーが中断を認識できなくなる可能性があります。ここでの他の回答のような単純なおもちゃの例では、フラグが復元されたかどうかは関係ありません。何もチェックされず、スレッドは終了します。

于 2015-10-30T16:50:44.520 に答える
1

割り込みの効果はInterruptedException、次にブロッキング操作が発生したときに をスローすることです (実際には、 をスローできることを指定するメソッドが次に呼び出されたときInterruptedException)。その時点で、通常どおり、通常のtry/catch実行フローに従います。これは実際に、および該当するesfinallyの後にブロックを実行します。trycatch

于 2013-01-29T06:18:19.063 に答える
0

中断前ではなく、try ブロックからの他の例外と同じように実行されます。

于 2013-01-29T06:29:45.310 に答える