JavaでSystem.exitを呼び出す必要がある場合


193

JavaではSystem.exit(0)、次のコードの有無にどのような違いがありますか?

public class TestExit
{      
    public static void main(String[] args)
    { 
        System.out.println("hello world");

        System.exit(0);  // is it necessary? And when it must be called? 
    }      
}

文書は言う:「このメソッドは正常に復帰することはありません。」どういう意味ですか?

回答:


207

System.exit()プログラムが終了する前にシャットダウンフックを実行するために使用できます。これは、プログラムのすべての部分がお互いを認識できない(そして認識してはならない)大きなプログラムでシャットダウンを処理する便利な方法です。次に、誰かが終了したい場合、彼は単にを呼び出すことができSystem.exit()、シャットダウンフック(適切に設定されている場合)は、ファイルのクローズ、リソースの解放など、必要なすべてのシャットダウンセレモニーを実行します。

「このメソッドは通常は戻りません。」メソッドが返らないことを意味します。スレッドがそこに行くと、それは戻ってきません。

プログラムを終了する別の、おそらくより一般的な方法は、単にmainメソッドの最後に到達することです。ただし、デーモン以外のスレッドが実行されている場合、それらはシャットダウンされないため、JVMは終了しません。したがって、そのような非デーモンスレッドがある場合、すべての非デーモンスレッドをシャットダウンして他のリソースを解放するには、(シャットダウンフック以外の)いくつかの他の手段が必要です。他の非デーモンスレッドがない場合、から戻るmainとJVMがシャットダウンされ、シャットダウンフックが呼び出されます。

何らかの理由でシャットダウンフックは過小評価され、誤解されているメカニズムのように思われ、人々はプログラムを終了するためにあらゆる種類の独自のカスタムハックを使ってホイールを再発明しています。シャットダウンフックの使用をお勧めします。とにかく使用するのは、標準ランタイムのすべてです。


10
「このメソッドは通常は戻りません。」メソッドが返らないことを意味します。スレッドがそこに行くと、それは戻ってきません。特に、これはSystem.exit(0)呼び出しを行うメソッドを単体テストできないことを意味します...
Bill Michell

5
-1不正解です。System.exitまたはmain()の終了が原因であるかどうかに関係なく、JVMが正常に終了すると、シャットダウンフックが実行されます。zx81 / doku / java / javadoc / j2se1.5.0 / docs / api / java / lang /…を
sleske

31
@sleske:他にデーモン以外のスレッドが存在する場合、main()の終了では不十分です。シャットダウンは、明示的にSystem.exit()を呼び出さない限り、最後の非デーモンスレッドが終了した後にのみ開始されます。これは、ランタイムドキュメントに明確に記載されています。
Joonas Pulakka

3
シャットダウンフックがSystem.exitを呼び出したスレッドに依存している場合、デッドロックになることに注意してください。
djechlin 2013年

8
追加するもの、誰かがランタイムを停止した場合、シャットダウンフックは実行されない(Runtime.getRuntime().halt()
Rogue

50

その場合、それは必要ありません。追加のスレッドは起動されません。終了コード(デフォルトは0)を変更していません-基本的にそれは無意味です。

ドキュメントがメソッドが正常に戻らないと言っている場合、それはコンパイラーが次のことを知らなくても、次のコード行は事実上到達できないことを意味します。

System.exit(0);
System.out.println("This line will never be reached");

例外がスローされるか、戻る前にVMが終了します。「ただ戻る」ことは決してありません。

System.exit()IMEを呼び出す価値があることは非常にまれです。コマンドラインツールを作成していて、例外をスローするだけでなく、終了コードを介してエラーを表示したい場合は理にかなっていますが、通常の製品コードで最後に使用したときのことを思い出せません。 。


2
コンパイラがそれを知らないのはなぜですか?System.exit()は、特定の検出コードを保証するのに十分なほど特別ではありませんか?
Bart van Heukelom、2010

3
@バート:いいえ、そうは思いません。このようなことのために言語に特別なケースを置くと、言語の複雑さが増し、ほとんどメリットがありません。
ジョンスキート

「二度と正常に戻ることはない」は、声明の「突然の完了」に関係していると私は思った。(JLSセクション14.1)。私が間違っている?
aioobe

@aioobe:いいえ、その通りです。System.exit()正常に完了することはありません-常に例外で完了するか、VMのシャットダウンで完了します(これはJLSでは実際にはカバーされていません)。
Jon Skeet

1
@piechuckerr:どうしてそう思うの?プログラムにエラーが発生したことを呼び出し側シェル(またはその他)に示すために、0以外の値でそれを呼び出すことは完全に合理的です。
Jon Skeet 2016年

15

それは世界の終わりであり、あなたのコードのどれも次に実行されないので、メソッドは決して戻りません。

例では、アプリケーションはコードの同じ場所で終了しますが、System.exitを使用する場合は、たとえば、カスタムコードを環境に返すオプションがあります。

System.exit(42);

終了コードを利用するのは誰ですか?アプリケーションを呼び出すスクリプト。Windows、Unix、およびその他すべてのスクリプト可能な環境で動作します。

なぜコードを返すのですか?「成功しなかった」、「データベースが応答しなかった」などと言います。

終了コードから値を取得し、それをUNIXシェルスクリプトまたはWindows cmdスクリプトで使用する方法を確認するには、このサイトでこの回答を確認してください。


14

System.exit(0)JVMを終了します。このような単純な例では、違いを理解するのは困難です。パラメータはOSに戻され、通常は異常終了(たとえば、ある種の致命的なエラー)を示すために使用されるため、バッチファイルまたはシェルスクリプトからjavaを呼び出した場合、この値を取得してアイデアを得ることができます。アプリケーションが成功した場合。

System.exit(0)アプリケーションサーバーにデプロイされたアプリケーションを呼び出すと、かなりの影響があります(試す前に考えてください)。


12

複雑なシャットダウンフックがある可能性のあるアプリケーションでは、このメソッドを不明なスレッドから呼び出さないでください。 System.exitJVMが終了するまで呼び出しがブロックされるため、通常は終了しません。終了する前に電源プラグが抜かれたコードが実行されているかのようです。呼び出すSystem.exitと、プログラムのシャットダウンフックが開始され、呼び出すスレッドはすべてSystem.exit、プログラムが終了するまでブロックされます。これは、シャットダウンフックSystem.exitが呼び出し元のスレッドにタスクを送信すると、プログラムがデッドロックすることを意味します。

私はこれを私のコードで次のように処理しています:

public static void exit(final int status) {
    new Thread("App-exit") {
        @Override
        public void run() {
            System.exit(status);
        }
    }.start();
}

System.exitが実際にJVMを終了しないという問題もありました。しかしそれは特定の条件下でのみ起こりました。私が取ったスレッドダンプは、どのスレッド/シャットダウンハンドラーがシャットダウンをブロックしているかについての洞察を与えませんでした。コメントに記載されているコードを使用することで解決しました!
カイ

7

答えは本当に役に立ちましたが、いくつかの追加の詳細が欠けていました。上記の答えに加えて、以下がJavaのシャットダウンプロセスを理解するのに役立つことを願っています:

  1. 通常のシャットダウンでは、JVMは最初にすべての登録済みシャットダウンフックを開始します。シャットダウンフックは、Runtime.addShutdownHookに登録されている開始されていないスレッドです。
  2. JVMは、シャットダウンフックが開始される順序を保証しません。アプリケーションスレッド(デーモンまたは非デーモン)がシャットダウン時にまだ実行されている場合、それらはシャットダウンプロセスと同時に実行され続けます
  3. すべてのシャットダウンフックが完了すると、runFinalizersOnExitがtrueの場合、JVMはファイナライザの実行を選択して停止する場合があります。
  4. JVMは、シャットダウン時にまだ実行中のアプリケーションスレッドを停止または中断しようとはしません。JVMが最終的に停止すると、これらは突然終了します。
  5. シャットダウンフックまたはファイナライザが完了しない場合、通常のシャットダウンプロセスが「ハング」し、JVMを突然シャットダウンする必要があります。
  6. 突然のシャットダウンでは、JVMはJVMを停止する以外に何もする必要はありません。シャットダウンフックは実行されません。

PS:JVMは、規則的または突然の方法でシャットダウンできます。

  1. 通常のシャットダウンは、最後の「通常の」(nondaemon)スレッドが終了したとき、誰かがSystem.exitを呼び出したとき、または他のプラットフォーム固有の手段(SIGINTの送信やCtrl-Cのヒットなど)によって開始されます。
  2. 上記は、JVMをシャットダウンするための標準的で好ましい方法ですが、Runtime.haltを呼び出すか、オペレーティングシステムを介してJVMプロセスを終了する(SIGKILLを送信するなど)ことによって、突然シャットダウンすることもできます。

7

System.exit(0)これらの理由で決して電話してはいけません:

  1. それは隠された「goto」であり、「gotos」は制御フローを壊します。このコンテキストでフックに依存することは、チーム内のすべての開発者が認識しなければならないメンタルマッピングです。
  2. プログラムを「正常に」終了すると、同じ終了コードがオペレーティングシステムに提供されるSystem.exit(0)ため、冗長になります。

    プログラムが「正常に」終了できない場合は、開発[デザイン]の制御を失っています。システム状態を常に完全に制御する必要があります。

  3. 停止していない実行中のスレッドなどのプログラミングの問題は、通常は非表示になります。
  4. 一貫性のないアプリケーション状態が発生し、スレッドが異常に中断される場合があります。(#3を参照)

ちなみに、プログラムの異常終了を示したい場合は、0以外の戻りコードを返すことは意味があります。


2
「常にシステム状態を完全に制御する必要があります。」これは、Javaでは不可能です。IoCフレームワークとアプリケーションサーバーは、システム状態の制御を放棄する非常に一般的で広く使用されている2つの方法にすぎません。そして、それはまったく問題ありません。
mhlz 2015

アプリケーションサーバーでSystem.exit(0)を実行して、サーバー管理者の反応について教えてください...この質問の件名と私の回答を見逃しました。
oopexpert 2015

多分私は十分に明確ではなかった。担当するシステム状態を常に完全に制御する必要があります。はい、一部の責任はアプリケーションサーバーとIoCにシフトされました。しかし、私はそれについて話していませんでした。
oopexpert 2015

5

System.exitが必要です

  • 0以外のエラーコードを返す場合
  • main()以外の場所からプログラムを終了する場合

あなたの場合、それは単純なreturn-from-mainとまったく同じことを行います。


後者とはどういう意味ですか?プログラムをシャットダウンする適切な方法は、すべてのスレッドを(適切に)停止することです。これは、メインスレッドから開始する必要のない移動です。そのため、exitそこに唯一のオプションがあるわけではありません。
Bart van Heukelom、2010

@バート:あなたが説明するのは、適切な方法ではなくプログラムをシャットダウンする可能な方法の1つです。シャットダウンフックを使用してすべてのスレッドを適切に停止することに問題はありません。また、シャットダウンフックはで起動されます。唯一のオプションではありませんが、間違いなく検討に値するオプションです。exit
Joonas Pulakka

しかし、ドキュメントから収集したものですが、シャットダウンフックは非常にデリケートであり、ユーザーが望んでいることを実行する時間があまりない場合があります。必ず、それらを使用して、OSシャットダウンなどの場合にうまく終了しますが、System.exit()を自分で呼び出す場合は、その前にシャットダウンコードを実行することをお勧めします(その後はおそらくシャットダウンしません) System.exit()がこれ以上必要です)
Bart van Heukelom

1
シャットダウンフックには、完了するまでにかかるすべての時間があります。すべてのフックが戻る前にVMが停止することはありません。実行に非常に長い時間がかかるシャットダウンフックを登録することで、VMの終了を防ぐことは確かに可能です。しかし、もちろん、シャットダウンシーケンスをさまざまな代替方法で実行することは可能です。
Joonas Pulakka

デーモン以外のスレッドが他にある場合、メインから戻ってもシャットダウンしません。
djechlin 2013年

4

Java言語仕様によると

プログラムの終了

プログラムはすべてのアクティビティを終了し、次の2つのいずれかが発生すると終了します。

デーモンスレッドではないすべてのスレッドが終了します。

一部のスレッドはクラスRuntimeまたはクラスSystemのexitメソッドを呼び出し、終了操作はセキュリティマネージャーによって禁止されていません。

これは、大きなプログラムがあり(少なくともこのプログラムよりも大きい)、実行を終了したい場合に使用する必要があることを意味します。


3

JVMで別のプログラムを実行していて、System.exitを使用している場合、その2番目のプログラムも閉じられます。たとえば、クラスターノードでJavaジョブを実行し、クラスターノードを管理するJavaプログラムが同じJVMで実行されているとします。ジョブがSystem.exitを使用する場合、ジョブを終了するだけでなく、「ノード全体をシャットダウン」します。管理プログラムが誤って閉じられたため、そのクラスターノードに別のジョブを送信できません。

したがって、同じJVM内の別のJavaプログラムからプログラムを制御できるようにする場合は、System.exitを使用しないでください。

意図的に完全なJVMを閉じたい場合、および他の回答で説明されている可能性を利用したい場合(たとえば、シャットダウンフック:Javaシャットダウンフック、コマンドラインのゼロ以外の戻り値)は、System.exitを使用します。呼び出し:WindowsバッチファイルでJavaプログラムの終了ステータスを取得する方法)。

また、ランタイム例外:System.exit(num)を確認するか、メインからRuntimeExceptionをスローしますか?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.