web-dev-qa-db-ja.com

JavaでSystem.exitを呼び出すべき時期

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? 
    }      
}

document はこう言っています: "このメソッドは正常に戻りません。"どういう意味ですか?

181
pierrotlefou

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

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

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

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

195
Joonas Pulakka

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

ドキュメントがメソッドが正常に返されないと言うとき、それはコンパイラがそれを知らないとしても、事実上到達不能であることを意味します。

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

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

System.exit() IMEを呼び出す価値があることは非常にまれです。コマンドラインツールを書いていて、単に例外をスローするのではなく終了コードでエラーを示したいのであれば意味がありますが、通常の本番コードで最後に使用したときのことは思い出せません。 。

48
Jon Skeet

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

あなたのアプリケーションは、あなたの例では、とにかくコードの同じ場所で終了するでしょう、しかしあなたがSystem.exitを使用するならば。次のように、カスタムコードを環境に返すことができます。

System.exit(42);

誰があなたの終了コードを利用するつもりですか?アプリケーションを呼び出したスクリプト。 Windows、Unix、その他すべてのスクリプト環境で動作します。

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

od終了コードの値を取得し、それをunix Shellスクリプトまたはwindows cmdスクリプトで使用する方法を確認するには、このサイトでこの回答を確認してください

15
mico

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

アプリケーションサーバーにデプロイされたアプリケーションでSystem.exit(0)を呼び出した場合は、非常に大きな影響があります(試す前に考えてみてください)。

14
Qwerky

複雑なシャットダウンフックを持つ可能性があるアプリケーションでは、このメソッドを未知のスレッドから呼び出さないでください。 JVMが終了するまで呼び出しがブロックされるため、System.exitは正常に終了しません。実行する前に、どんなコードが実行されていても、電源プラグが差し込まれているかのようです。 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();
}
10
djechlin

System.exit(0)を呼び出さないでください。

  1. それは隠された "後藤"であり、 "gotos"は制御フローを壊します。この文脈でフックに頼ることは、チームのすべての開発者が知っておくべき精神的なマッピングです。
  2. プログラムを「正常に」終了すると、System.exit(0)と同じ終了コードがオペレーティングシステムに提供されます。だから冗長です。プログラムが「正常に」終了できないと、開発は制御できなくなりました。あなたは常にシステム状態を完全に制御する必要があります。
  3. 通常停止していないスレッドを実行するなどのプログラミングの問題を隠します。
  4. これは3を参照しています。矛盾するアプリケーション状態がスレッドを異常に中断している可能性があります。

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

7
oopexpert

答えは本当に役に立ちましたが、いくらか余分な詳細を見逃していた方法もあります。上記の回答に加えて、以下がJavaでのシャットダウンプロセスの理解に役立つことを願っています。

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

シモンズ:JVMは整然とまたは突然のいずれかの方法でシャットダウンできます。

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

System.exitが必要です

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

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

5
mfx

Java言語仕様 と言っている

プログラム終了

プログラムはすべてのアクティビティを終了させ、次の2つのうちの1つが起こると終了します。

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

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

つまり、あなたが大きなプログラムを持っていて(少なくとも、これよりも大きい)、その実行を終了したいときには、それを使うべきです。

4
Marcin Szymczak

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

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

故意にJVM全体を閉じたい場合や、他の答えで説明されている可能性を利用したい場合(たとえばシャットダウンフック: Java shutdown hook 、non)には、System.exitを使用してください。コマンドライン呼び出しの-zero戻り値: WindowsバッチファイルでJavaプログラムの終了ステータスを取得する方法 )。

ランタイム例外も見てください。 System.exit(num)またはmainからRuntimeExceptionをスローしますか?

3
Stefan