35

チームメイトは次のように主張しました。

Thread.interrupt()本質的に壊れており、(ほとんど)使用しないでください」.

なぜそうなのかを理解しようとしています。

決して使用しないことが既知のベストプラクティスThread.interrupt()ですか? それが壊れている/バグがあり、堅牢なマルチスレッドコードを書くために使用すべきではない理由を証明できますか?

- この質問がデザインの防腐剤から「きれい」である場合、私はこの質問には興味がありません。私の質問は - バグがありますか?

4

7 に答える 7

47

短縮版:

Thread.interrupt() を使用しないことが既知のベスト プラクティスですか?

いいえ。

それが壊れている/バグがあり、堅牢なマルチスレッドコードを書くために使用すべきではない理由を証明できますか?

その逆です。マルチスレッド コードでは重要です。

例については、 Java Concurrency in Practiceのリスト 7.7 を参照してください。

より長いバージョン:

ここでは、このメソッドを 1 つの特定の場所で使用します: handlingInterruptedExceptionsです。少し奇妙に思えるかもしれませんが、コードでは次のようになります。

try {
    // Some code that might throw an InterruptedException.  
    // Using sleep as an example
    Thread.sleep(10000);
} catch (InterruptedException ie) {
    System.err.println("Interrupted in our long run.  Stopping.");
    Thread.currentThread().interrupt();
}

これにより、次の 2 つのことが行われます。

  1. 割り込み例外を食べないようにします。IDE の自動例外ハンドラは、常にie.printStackTrace();「TODO: 何か便利なものが必要です!」のようなものを提供します。コメント。
  2. このメソッドでチェック例外を強制することなく、割り込みステータスを復元します。throws InterruptedException実装しているメソッド シグネチャに句がない場合、これは中断されたステータスを伝達するための別のオプションです。

コメンターは、「スレッドを強制的に終了させるために」未チェックの例外を使用する必要があると提案しました。これは、スレッドを突然強制終了することが適切なことであるという事前の知識があることを前提としています。私はしません。

上記のリストの前のページで、JCIP の Brian Goetz を引用すると、次のようになります。

タスクは、特定の中断ポリシーを持つサービス内で実行するように明示的に設計されていない限り、実行中のスレッドの中断ポリシーについて何も想定しないでください。

たとえば、私がこれをしたと想像してください:

} catch (InterruptedException ie) {
    System.err.println("Interrupted in our long run.  Stopping.");
    // The following is very rude.
    throw new RuntimeException("I think the thread should die immediately", ie);
}

私は、コール スタックの残りの他の義務と関連する状態に関係なく、このスレッドは今すぐ終了する必要があると宣言します。他のすべての catch ブロックとステート クリーンアップ コードをこっそり通り過ぎて、スレッドの死に直行しようとします。さらに悪いことに、スレッドの割り込みステータスを消費していたでしょう。アップストリーム ロジックは、プログラム ロジック エラーがあったのか、それともチェック済み例外を不明瞭なラッパー内に隠そうとしているのかを突き止めるために、例外を分解する必要があります。

たとえば、チームの他の全員がすぐにやらなければならないことは次のとおりです。

try {
    callBobsCode();
} catch (RuntimeException e) { // Because Bob is a jerk
    if (e.getCause() instanceOf InterruptedException) {
        // Man, what is that guy's problem?
        interruptCleanlyAndPreserveState();
        // Restoring the interrupt status
        Thread.currentThread().interrupt();
    }
}

中断された状態は、特定の よりも重要ですInterruptException。理由の具体例については、Thread.interrupt()の javadoc を参照してください。

このスレッドが Object クラスの wait()、wait(long)、または wait(long, int) メソッド、または join()、join(long)、join(long, int) の呼び出しでブロックされている場合、sleep(long)、または sleep(long, int)、このクラスのメソッドの場合、その割り込みステータスはクリアされ、InterruptedException を受け取ります。

ご覧のとおり、割り込み要求が処理されるときに複数の InterruptedException が作成および処理される可能性がありますが、その割り込みステータスが保持されている場合に限られます。

于 2010-01-07T15:02:12.817 に答える
16

私が知っている唯一の方法は、それThread.interrupt()が壊れているように見えることを実際には実行しないということです。実際には、それをリッスンするコードのみを中断できます。

ただし、適切に使用すると、タスク管理とキャンセルのための優れた組み込みメカニズムのように思えます。

Java Concurrency in Practiceを適切かつ安全に使用する方法について詳しく読むことをお勧めします。

于 2010-01-07T14:45:21.927 に答える
12

の主な問題Thread.interrupt()は、ほとんどのプログラマーが隠れた落とし穴を知らず、間違った方法で使用していることです。たとえば、割り込みを処理するときに、フラグをクリアするメソッドがあります (そのため、ステータスが失われます)。

また、呼び出しが常にすぐにスレッドを中断するとは限りません。たとえば、何らかのシステム ルーチンでハングした場合、何も起こりません。実際、スレッドがフラグをチェックせず、 をスローする Java メソッドをまったく呼び出さない場合、スレッドInterruptExceptionを中断しても何の効果もありません。

于 2010-01-07T14:43:32.320 に答える
4

いいえ、バグではありません。これは、実際に Java でスレッドを停止する方法の基礎です。java.util.concurrent の Executor フレームワークで使用されます - の実装を参照してくださいjava.util.concurrent.FutureTask.Sync.innerCancel

失敗に関しては、私はそれが失敗するのを見たことがなく、私はそれを広範囲に使用してきました.

于 2010-01-07T15:10:37.557 に答える
1

言及されていない理由の1つは、割り込み信号が失われる可能性があり、Thread.interrupt()メソッドの呼び出しが無意味になることです。したがって、Thread.run()メソッドのコードがwhileループで回転していない限り、Thread.interrupt()を呼び出した結果は不確実です。

于 2012-10-11T10:33:46.073 に答える
-3

問題は、実装にバグがないことではなく、スレッドが中断されたときにスレッドが不明な状態にあり、これが予期しない動作につながる可能性があることです。

于 2010-01-07T14:45:21.117 に答える