web-dev-qa-db-ja.com

誰もinterrupt()を呼び出さない場合、InterruptedExceptionを無視しても大丈夫ですか?

自分のスレッド(つまり、スレッドプールではない)を作成し、sleepまたは他の割り込み可能なメソッドを呼び出す場合、コード内で他に誰も知らない場合、InterruptedExceptionを無視してもかまいませんスレッドで割り込みを行っています

言い換えると、JVMがスレッドに割り込みできない限り、スレッドが存続することになっている場合、InterruptedExceptionはnever呼び出されるため、例外を飲み込むことができますか?

37
Hilikus

チェックされた例外を無視しても安全とは見なされません。
現時点では大丈夫かもしれませんが、別のプログラマーがコードを拡張する場合、標準的な動作、つまり割り込み呼び出しに反応するスレッドを期待します。
また、この場合、空のcatchブロックは危険です。これは、JVMが割り込みフラグを削除し、間違いなく再設定する必要があるためです。

Thread.currentThread().interrupt();

catchブロック内。私の意見では、これはInterruptedExceptionsの最小キャッチ実装です。ループ内のisInterruptedフラグをチェックしても、それほど害はありません。
プロジェクトが少し成長したため、予期しないスレッドの動作を1〜2日検索するプログラマー自身の面倒に比べると、オーバーヘッドはほとんどありません。

コードの可読性がこれらのcatchの実装に苦しんでいると感じた場合は、独自のsafeSleepユーティリティメソッドを実装して、Exceptionsを処理し、フラグを適切に設定できます。

一方、ハードウェア障害の場合、InterruptedExceptionはJVM自体によってスローされません。これはユーザーがExceptionのみを指定したものです。 したがって、Threads参照を伝播しない場合、その上でThread.interrupt()を呼び出すことができる他のThreadsはありません。 それだけです技術的にしかし、人的要因とプログラムの進化を過小評価すべきではありません。
編集:ruakhが指摘したように、実際にはThreads参照を取得する方法があります。 Thread.interrupt()呼び出しをスケジュールします。そうすれば、熱中の開発者は、中断できないThreadを実装するクラスを見る必要さえないかもしれません。私の意見では、適切な例外処理を実装することは別の理由です。
別のことExceptionをスローしない場合は、INFOを超えるレベルでそのようなイベントをログに記録することをお勧めします。

32
Zhedar

それを飲み込む代わりに、それが絶対に起こらないと確信しているなら、それを無視する代わりにクラッシュすることができます。たとえば、Error(またはRuntimeException)をスローします。

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    throw new Error(e);
}

エラーのJavadoc から:

エラーはThrowableのサブクラスであり、合理的なアプリケーションがキャッチしようとしてはならない重大な問題を示します。このようなエラーのほとんどは異常な状態です。

何かが決して起こらないと仮定する価値があると思うなら、もしそれが起こるなら、それは「異常な状態」であり、知っている人はただ「深刻な問題」かもしれない。

これを見るもう1つの方法は、将来誰かがdoesメソッドを中断した場合に、あたかも実行を継続することを望んでいる可能性があるということです。何も起こらなかった?いいえと思います。

32
Dan Getz

例外が発生してはならないと思われる場合は、例外を決して飲み込むべきではありません。決して発生しないが発生してはならない条件を処理するコードを追加しないことを決定しても構いませんサイレント

最低限行うべきことは:

catch(InterruptedException ex) {
  throw new AssertionError(ex);
}

これにより、これが絶対に発生しないという主張が間違っている場合は必ず、それに気付くようになります。このパターンは、他の予期しない例外にも適用されます。 IOExceptionは、ターゲットOutputStreamByteArrayOutputStreamであるか、AppendableFormatterStringBuilderなど.


ところで、Thread.sleepに代わるものがあり、InterruptedExceptionをまったく処理する必要はありません。

LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(timeInMillis));

このメソッドは、スレッドが中断されたときに以前に戻り、Threadの中断状態を保持するため、コードが他の誰かによって使用されている場合に適切な処理を既に提供しますdoes割り込みを使用します(コードの呼び出し元が割り込み状態をチェックすると仮定します)。

16
Holger

私はまだこれらの問題に関する聖書を検討している本、Goetz et al。 実践におけるJavaの同時実行性は、第7章で以下の重要な部分を述べています(かなり同じ内容がGoetzの developerWorksの記事 にあります、これは無料であるという利点がありますが、本はいくつかの点でもう少し明確です。)

中断は協調的なメカニズムです。あるスレッドは、別のスレッドにそれがしていることを止めさせ、他の何かをさせることはできません。スレッドAがスレッドBを中断するとき、Aは、Bが便利な停止ポイントに到達したときに、Bが実行していることを停止するように単に要求しているだけです。

[...]

スレッドの割り込みポリシーを実装するコードのみが割り込み要求を飲み込む可能性があります。汎用タスクおよびライブラリコードは、割り込み要求を決して飲み込まないでください。

ですから、はい、あなたが概説した状況下でInterruptedExceptionを「飲み込む」ことができます。

本の重要なポイント:

各スレッドには独自の割り込みポリシーがあるため、割り込みの意味がわからない限り、スレッドを中断しないでください。

したがって、RuntimeExceptionAssertionErrorを使用した「クラッシュ」などの独自のポリシーを選択し、警告としてログに記録するか、この問題を他の人に文書化する限り、中断を完全に無視できます。知るために。最適なものは、スレッドが実際に何をしているかに依存し、その詳細はまだ提供していません。たとえば、ロケットで実行している場合(姿勢制御を行うなど)、JVM /ロケットをクラッシュさせたくないのは、仲間のプログラマー(あなたと同じ会社で働いていないかもしれないからです)彼はあなたが呼ぶライブラリを書きました]彼のコードのどこかで特定の契約を忘れて、あなたに安全に無視できる例外をダンプします: "発生した例外はランダムな失敗ではなく、設計エラーです。"

9
Fizz

Projektが大きくなり、より複雑になった場合、誰も割り込みメソッドを呼び出さないと断言するのは難しくなっています。誰かがいつかこのメソッドを呼び出し、InterruptedExceptionが発生した場合、少なくともどこかにログを記録しないと、デバッグが非常に難しくなります。

7
Jan

無視すべきではありません。呼び出し元にスローバックするか、例外がスローされるとクリアされるスレッドの割り込みステータスを再アサートする必要があります。

catch (InterruptedException e) { 
     // Restore the interrupted status
     Thread.currentThread().interrupt();
 }

キャッチ後に速やかにスレッドを終了しない限り。

ここInterruptedExceptionsの取り扱いに関する記事です。

6
manouti

私は、InterruptedExceptionを無視することは安全かどうか、そのスレッドで何をしているかに依存すると思います。スレッドへの不要な割り込みがシステムまたはリソースを不要な状態(ダーティ、ロック、解放されていないためリソースのリークを引き起こす可能性がある)のままにする可能性があるシナリオがある場合、InterruptedExceptionを処理する責任は無視するべきではありません。スレッドを割り込み可能にするかどうかは、あなた次第です。

つまり、割り込みメカニズムは、主にキャンセルポリシーとタスクのクリーンアップの実装に使用されます。 IntrruptedExceptionを無視することは、政治的に正しいとは思えないかもしれませんが、タスクでクリーンアップするものがないか、特定のタスクキャンセルポリシーを持っていませんか?.

1
Mak