InterruptedException
を処理する次の方法の違いは何ですか?それを行う最良の方法は何ですか?
try{
//...
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
OR
try{
//...
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
編集:これらの2つがどのシナリオで使用されているかも知りたいです。
InterruptedExceptionを処理する次の方法の違いは何ですか?それを行う最良の方法は何ですか?
InterruptedException
をスローするメソッドを呼び出したので、おそらくこの質問をするようになるでしょう。
まず、throws InterruptedException
が何であるかを確認する必要があります。メソッドシグネチャの一部と、呼び出しているメソッドを呼び出した結果の可能性。そのため、InterruptedException
はメソッド呼び出しの完全に有効な結果であるという事実を受け入れることから始めます。
今、あなたが呼び出しているメソッドがそのような例外をスローする場合、yourメソッドは何をすべきですか?次のことを考えて答えを理解できます。
メソッドにとって意味がありますかyouはInterruptedException
?をスローするように実装していますInterruptedException
yourメソッドを呼び出したときの賢明な結果?
yesの場合、throws InterruptedException
はyourメソッドシグネチャの一部である必要があり、例外を伝播させる必要があります(つまり、まったくキャッチしません)。
例:メソッドは、ネットワークからの値を待って計算を終了し、結果を返します。ブロッキングネットワーク呼び出しが
InterruptedException
をスローする場合、メソッドは通常の方法で計算を終了できません。InterruptedException
を伝播させます。int computeSum(Server server) throws InterruptedException { // Any InterruptedException thrown below is propagated int a = server.getValueA(); int b = server.getValueB(); return a + b; }
noの場合、throws InterruptedException
を使用してメソッドを宣言しないでください。例外をキャッチする必要があります。この状況では、次の2つの点に注意する必要があります。
誰かがあなたのスレッドを中断しました。おそらく誰かが操作をキャンセルしたり、プログラムを正常に終了したりすることを望んでいます。あなたはその人に礼儀正しく、さらなる苦労なしにあなたの方法から戻るべきです。
yourメソッドは、InterruptedException
の場合に適切な戻り値を生成することができますが、スレッドが中断されたという事実は依然として重要です。特に、メソッドを呼び出すコードは、メソッドの実行中に割り込みが発生したかどうかに関心がある場合があります。したがって、中断フラグを設定して、中断が発生したという事実をログに記録する必要があります:Thread.currentThread().interrupt()
例:ユーザーは2つの値の合計を印刷するように要求しました。 「
Failed to compute sum
」の印刷は、合計を計算できない場合は許容できます(InterruptedException
によるスタックトレースでプログラムをクラッシュさせるよりもはるかに優れています)。つまり、このメソッドをthrows InterruptedException
で宣言することはnot意味があります。void printSum(Server server) { try { int sum = computeSum(server); System.out.println("Sum: " + sum); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // set interrupt flag System.out.println("Failed to compute sum"); } }
今では、throw new RuntimeException(e)
を実行するだけでは悪い考えであることは明らかです。発信者にあまり丁寧ではありません。新しいランタイム例外を作成することもできますが、根本的な原因(スレッドに実行を停止させたい人)が失われる可能性があります。
他の例:
Runnable
の実装:お気づきかもしれませんが、Runnable.run
のシグネチャはInterruptedExceptions
の再スローを許可していません。さて、youはRunnable
の実装にサインアップしました。つまり、youはInterruptedExceptions
の可能性に対処するためにサインアップしました。Callable
などの別のインターフェースを選択するか、上記の2番目のアプローチに従います。
Thread.sleep
の呼び出し:ファイルを読み取ろうとしていますが、1秒の間隔で10回試行する必要があります。Thread.sleep(1000)
を呼び出します。したがって、InterruptedException
を処理する必要があります。tryToReadFile
などのメソッドの場合、「中断された場合、ファイルを読み取ろうとするアクションを完了できません」と言うのは完全に理にかなっています。言い換えると、メソッドがInterruptedExceptions
をスローすることは完全に理にかなっています。String tryToReadFile(File f) throws InterruptedException { for (int i = 0; i < 10; i++) { if (f.exists()) return readFile(f); Thread.sleep(1000); } return null; }
この投稿は記事として書き直されました here 。
たまたま私は今朝、ブライアン・ゲッツによる Java並行性の実践 で仕事をする方法について読んでいたところです。基本的に彼は、あなたが2つのことのうちの1つをするべきだと言います
InterruptedException
を伝播します-メソッドを宣言して、チェックされたInterruptedException
をスローして、呼び出し元が処理するようにします。
割り込みを復元する-InterruptedException
をスローできないことがあります。これらの場合、InterruptedException
をキャッチし、currentThread
でinterrupt()
メソッドを呼び出して割り込みステータスを復元し、呼び出しスタックの上位のコードで割り込みが発行されたことを確認する必要があります。
あなたは何をしようとしているのですか?
InterruptedException
は、スレッドが待機中またはスリープ中のときにスローされ、別のスレッドがクラスinterrupt
のThread
メソッドを使用してスレッドを中断します。したがって、この例外をキャッチすると、スレッドが中断されたことを意味します。他の場所からスレッドの「中断」状態を確認したい場合を除き、通常、Thread.currentThread().interrupt();
を再度呼び出すことは意味がありません。
RuntimeException
をスローする他のオプションについては、実行するのが賢明なことではないようです(誰がこれをキャッチしますか?それをどのように処理しますか?)。
私にとってこれについての重要なことは、InterruptedExceptionが問題になることではなく、スレッドがあなたが指示したことを実行することです。したがって、RuntimeExceptionにラップして再スローするのは意味がありません。
多くの場合、RuntimeExceptionにラップされた例外を再スローするのは理にかなっています。ここで何が間違っていたのかわからず、修正することもできません。現在の処理フローから抜け出すだけです。アプリケーション全体の例外ハンドラをヒットして、ログに記録できるようにします。これは、InterruptedExceptionの場合ではなく、interrupt()が呼び出されたことに応答するスレッドであり、タイムリーにスレッドの処理をキャンセルするためにInterruptedExceptionをスローしています。
したがって、InterruptedExceptionを伝達するか、インテリジェントに(意図したとおりの処理を実行した場所で)実行し、割り込みフラグをリセットします。 InterruptedExceptionがスローされると、割り込みフラグがクリアされることに注意してください。 Jdkライブラリ開発者が行う前提は、例外をキャッチすると処理することになるため、デフォルトでフラグはクリアされます。
したがって、間違いなく最初の方法の方が良いです、質問で2番目に投稿された例は、スレッドが実際に中断されることを期待しない限り有用ではなく、中断するとエラーになります。
ここに私が書いた答えがあります 例で割り込みの仕組みを説明します 。例のコードで、InterruptedExceptionを使用してRunnableのrunメソッドのwhileループから抜け出していることがわかります。
正しいデフォルトの選択は、あなたのスローリストにInterruptedExceptionを追加することです。割り込みは、別のスレッドがスレッドの終了を望んでいることを示します。このリクエストの理由は明らかにされておらず、完全にコンテキストに基づいているため、追加の知識がない場合は単なるシャットダウンであると想定する必要があり、シャットダウンを回避するものは非友好的な応答です。
JavaがInterruptedExceptionをランダムにスローすることはありません。すべてのアドバイスがアプリケーションに影響することはありませんが、開発者が「飲み込む」戦略に従うことが非常に不便になる場合があります。チームは多数のテストを開発し、Thread.Sleepを多く使用していました。 CIサーバーでテストの実行を開始しましたが、コードの欠陥が原因で永続的な待機が発生する場合がありました。状況を悪化させるために、CIジョブをキャンセルしようとしても、テストを中止することを意図したThread.Interruptがジョブを中止しなかったため、CIジョブは閉じられませんでした。ボックスにログインし、プロセスを手動で強制終了する必要がありました。
要するに、InterruptedExceptionを単にスローした場合、スレッドを終了するというデフォルトの意図に一致しています。スローリストにInterruptedExceptionを追加できない場合は、RuntimeExceptionでラップします。
InterruptedException自体がRuntimeExceptionである必要があるという非常に合理的な議論があります。これにより、「デフォルト」の処理が改善されるためです。 RuntimeExceptionはコード内のエラーを表すべきであるというカテゴリルールに固執しているため、RuntimeExceptionではありません。 InterruptedExceptionはコードのエラーから直接発生するものではないため、発生しません。しかし、実際には、コードにエラーがあるため(つまり、無限ループ、デッドロック)、InterruptedExceptionが頻繁に発生し、割り込みはそのエラーを処理するための他のスレッドのメソッドです。
合理的なクリーンアップが行われていることがわかっている場合は、実行してください。割り込みのより深い原因がわかっている場合は、より包括的な処理を行うことができます。
要約すると、処理の選択は次のリストに従う必要があります。
ほとんどの人や記事が言及しているものに最後のオプションを追加したかっただけです。 mR_fr0gが述べているように、次のいずれかの方法で割り込みを正しく処理することが重要です。
InterruptExceptionの伝播
スレッドの割り込み状態を復元
またはさらに:
状況に応じてカスタムの方法で割り込みを処理しても問題はありません。割り込みは強制的なコマンドとは異なり、終了の要求であるため、アプリケーションが要求を適切に処理できるように追加の作業を完了することは完全に有効です。たとえば、スレッドがスリープし、IOまたはハードウェアの応答を待っている場合、割り込みを受信すると、スレッドを終了する前に接続を正常に閉じることは完全に有効です。
このトピックを理解することを強くお勧めしますが、この記事は情報源として優れています。 http://www.ibm.com/developerworks/Java/library/j-jtp05236/
場合によっては何もしなくても大丈夫だと思います。おそらくデフォルトで行うべきことではありませんが、割り込みを発生させる方法がない場合は、他に何をすべきかわかりません(おそらくエラーをログに記録しますが、プログラムフローには影響しません)。
1つのケースは、タスク(ブロッキング)キューがある場合です。これらのタスクを処理するデーモンスレッドがあり、自分でスレッドを中断しない場合(私の知る限り、jvmはjvmシャットダウン時にデーモンスレッドを中断しません)、割り込みが発生する方法がありません。ただ無視されます。 (デーモンスレッドはいつでもjvmによって強制終了される可能性があることを知っているため、場合によっては不適切です)。
編集:別のケースは、少なくともOracleのチュートリアルに基づいて、保護されたブロックである可能性があります: http://docs.Oracle.com/javase/tutorial/essential/concurrency/guardmeth.html