web-dev-qa-db-ja.com

JavaプログラムのメインスレッドでSystem.exit(0)とThread.currentThread()。interrupt()を呼び出すことの違いは何ですか?

どちらもプログラムの実行を停止します。ただし、これがどのように発生するかにはいくつかの違いがあるはずです。彼らは何ですか?

21
brandones

概要

  1. thread.interrupt()はスレッドを停止しません。マルチスレッドプログラムでの調整に使用されます。自分が何をしているのかを正確に理解していない限り、使用しないでください。
  2. RuntimeExceptionをスローすると、(通常は)スレッドが終了しますが、必ずしもプログラムが終了するわけではありません。
  3. System.exit(int)mostは常にプログラムを終了し、ステータスコードを返します。
  4. 異常な状況では、System.exit(int)が実際にプログラムを停止しない場合があります。一方、Runtime.getRuntime().halt(int)は、常に実行します。

スレッドの中断

あなたの最初の文が間違っているのではないかと思います。 Thread.currentThread().interrupt()はスレッドまたはプログラムを停止しません。

スレッドの中断は、スレッドがshould停止したことを通知する方法ですが、これは協力的な取り組みです。スレッド内のコードは、中断されたステータスを時々チェックすることになっています。そして(ほとんどの場合-しかしこれもオプションです)が中断された場合は停止する必要があります。そうしないと何も起こりません。

具体的には、スレッド(任意のスレッド、現在実行中のスレッドを含む)に割り込むと、interruptedフラグのみが設定されます。標準ライブラリの特定のメソッドはInterruptedExceptionをスローしますが、これはスレッドが中断されたことを通知する方法でもあります。このような状況で何をすべきかは、そのスレッドで実行されているコード次第です。

BrianGoetzによるJava Concurrency in Practice本の関連部分は次のとおりです。

スレッドは、スレッドを中断し、スレッドが中断されたかどうかを照会するための割り込みメソッドを提供します。各スレッドには、中断されたステータスを表すブールプロパティがあります。スレッドに割り込むと、このステータスが設定されます。

中断は協調的なメカニズムです。あるスレッドが別のスレッドに、実行中の処理を停止して他のことを強制することはできません。スレッドAがスレッドBに割り込むとき、Aは、都合のよい停止ポイントに到達したときに、Bが実行していることを停止するように要求しているだけですが、APIまたは言語仕様には、特定のアプリケーションレベルのセマンティクスを要求するものはありません。中断、中断の最も賢明な使用法は、アクティビティをキャンセルすることです。中断に対応するブロック方法により、長時間実行されているアクティビティをタイムリーにキャンセルすることが容易になります。

例外とSystem.exit(int)

System.exit(int) のJavadocは次のように述べています。

現在実行中のJava仮想マシンを終了します。引数はステータスコードとして機能します。慣例により、ゼロ以外のステータスコード異常終了を示します。

したがって、exit()を呼び出すと、(ほぼ)確実にプログラムが停止します。 RuntimeException(またはError)をスローするのとは対照的に、これはコールスタックのどこかでキャッチできず、他のスレッドが実行されているかどうかにも依存しません。一方、キャッチされない例外は、スローされたスレッドを終了しますが、他の(デーモン以外の)スレッドがある場合、プログラムは引き続き実行されます。

例外をスローすることとのもう1つの違いは、exit()はコンソールに何も出力せず(キャッチされない例外と同様)、代わりにプログラムに特定のステータスコードを返すことです。ステータスコードは、シェルまたはバッチスクリプトで使用されることがありますが、それ以外はあまり役に立ちません。

Runtime.halt(int)

最後に(完全を期すために)、Javaプログラムを終了する3番目の可能性を指摘したいと思います。System.exit(int)が呼び出されたとき(またはプログラムがいくつかで終了したとき)他の方法)、ランタイムはJava仮想マシンが停止する前にいくつかのクリーンアップ作業を行います。これは Runtime.exit(int) のJavadocで説明されています(これはSystem.exit(int)によって呼び出されます:

仮想マシンのシャットダウンシーケンスは、2つのフェーズで構成されます。最初のフェーズでは、登録されているすべてのシャットダウンフックが存在する場合、不特定の順序で開始され、終了するまで同時に実行できます。第2フェーズでは、終了時のファイナライズが有効になっている場合、呼び出されていないすべてのファイナライザーが実行されます。これが完了すると、仮想マシンは停止します。

deadlock などの理由でシャットダウンフックまたはファイナライザーの完了が妨げられた場合、プログラムが実際に終了することはありません。 JVMが停止することを保証する唯一のメソッドは Runtime.halt(int) :です。

この方法は、細心の注意を払って使用する必要があります。 exitメソッドとは異なり、このメソッドではシャットダウンフックが開始されず、finalization-on-exitが有効になっている場合は呼び出されないファイナライザーが実行されません。

38
rolve

他の(デーモン以外の)スレッドが実行されている場合、メインスレッドを停止してもJVMは終了しません。 System.exit()は、他のすべてのスレッドを強制終了します。

18
SJuan76

マルチスレッドアプリケーションでは、を実行しているスレッドが複数あります。 Thread.currentThread().interrupt()は現在実行中のスレッドのみを中断しますが、メインスレッドが中断された場合でも、残りのスレッドは実行されます。

一方、System.exit(0)の結果、システムは終了します。そして、すべてのスレッドが強制終了されます。

1
Rohit Jain