我们何时应该在Java中调用System.exit

pie*_*fou 191 java 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? 
    }      
}
Run Code Online (Sandbox Code Playgroud)

文件说:"这种方法永远不会正常返回." 这是什么意思?

Joo*_*kka 202

System.exit()可以用来在程序退出之前运行关闭挂钩.这是处理在更大的计划停机,在程序的所有部分不能(也不应该)知道彼此的一种便捷方式.那么,如果有人想退出,他可以简单地调用System.exit()和关闭挂钩(如果设置正确)采取做一切必要的关机仪式,如关闭文件,释放资源等的护理

"这种方法永远不会正常返回." 意味着该方法不会返回; 一旦一个线程进入那里,就不会再回来了.

退出程序的另一种可能更常见的方法是简单地到达main方法的末尾.但是如果有任何非守护程序线程在运行,它们将不会被关闭,因此JVM将不会退出.因此,如果您有任何此类非守护程序线程,则需要一些其他方法(而不是关闭挂钩)来关闭所有非守护程序线程并释放其他资源.如果没有其他非守护程序线程,则返回main将关闭JVM并将调用关闭挂钩.

出于某种原因,关机钩子似乎是一种被低估和误解的机制,人们正在用各种专有的自定义黑客重新发明轮子以退出他们的程序.我鼓励使用关机钩子; 无论如何,你将在标准运行时使用它.

  • @sleske:如果有其他非守护进程线程,则终止main()是不够的.除非您显式调用System.exit(),否则只有在最后一个非守护程序线程终止后才会启动关闭.这在Runtime文档中有明确说明. (30认同)
  • "这种方法永远不会正常返回." 意味着该方法不会返回; 一旦一个线程进入那里,就不会再回来了.请特别注意,这意味着您无法对进行System.exit(0)调用的方法进行单元测试... (9认同)
  • 要添加的东西,如果有人停止运行时,关闭钩子将无法运行(`Runtime.getRuntime().halt()`) (6认同)
  • -1不正确.如果JVM正常终止,无论是因为System.exit还是终止main(),都会运行关闭挂钩.见http://zx81/doku/java/javadoc/j2se1.5.0/docs/api/java/lang/Runtime.html#addShutdownHook%28java.lang.Thread%29 (5认同)
  • 请注意,如果您的关闭钩子依赖于调用System.exit的线程,您将死锁. (3认同)
  • 我的同事曾经向我展示了一个技巧,以确保`System.exit()`会抛出一些安全异常而不是退出Java.不记得它是什么,但它允许他单元测试一个可能调用`System.exit()`的方法.还有一个案例就是不要过度使用`System.exit()`,我应该想一想. (2认同)

Jon*_*eet 49

在那种情况下,它不是必需的.没有额外的线程将被启动,你不会更改退出代码(默认为0) - 基本上它没有意义.

当文档说方法永远不会正常返回时,这意味着后续的代码行实际上是无法访问的,即使编译器不知道:

System.exit(0);
System.out.println("This line will never be reached");
Run Code Online (Sandbox Code Playgroud)

将抛出异常,或者VM将在返回之前终止.它永远不会"回归".

值得打电话给System.exit()IME 是非常罕见的.如果您正在编写命令行工具,并且想要通过退出代码指示错误而不是仅仅抛出异常,这是有意义的...但我不记得上次我在正常的生产代码中使用它了.

  • @Bart:不,我不这么认为.在这种事情的语言中加入特殊情况会增加语言的复杂性而几乎没有什么好处. (3认同)
  • 为什么编译器不知道呢?System.exit()是否足够特殊以保证特定的检测代码? (2认同)

mic*_*ico 15

该方法永远不会返回,因为它是世界末日,并且下一个代码都不会被执行.

在您的示例中,您的应用程序无论如何都会在代码中的相同位置退出,但是,如果您使用System.exit.您可以选择将自定义代码返回到环境中,比如说

System.exit(42);
Run Code Online (Sandbox Code Playgroud)

谁将使用您的退出代码?一个调用应用程序的脚本.适用于Windows,Unix和所有其他可编写脚本的环境.

为什么要返回代码?要说"我没有成功","数据库没有回答".

要了解如何获取退出代码的值并在unix shell脚本或windows cmd脚本中使用它,您可以在此站点上查看此答案


Qwe*_*rky 14

System.exit(0)终止JVM.在这样的简单例子中,很难理解差异.该参数被传递回OS并且通常用于指示异常终止(例如某种致命错误),因此如果您从批处理文件或shell脚本调用java,您将能够获得此值并获得一个想法如果申请成功.

如果您调用System.exit(0)部署到应用程序服务器的应用程序(在尝试之前考虑它),这将产生相当大的影响.


dje*_*lin 11

在可能具有复杂关闭挂钩的应用程序中,不应从未知线程调用此方法. System.exit从来没有正常退出,因为调用将阻塞,直到JVM终止.这是因为如果任何代码运行在其上有电源插头拔出,才可以完成.调用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();
}
Run Code Online (Sandbox Code Playgroud)


小智 7

永远不应该调用System.exit(0).

  1. 它是一个隐藏的"goto",而"gotos"打破了控制流程.在这种情况下依赖钩子是团队中每个开发人员必须注意的心理映射.
  2. "正常"退出程序将为System.exit(0)提供与操作系统相同的退出代码.所以这是多余的.如果您的程序无法"正常"退出,则您的开发失控.您应该始终完全控制系统状态.
  3. 您隐藏编程问题,例如运行未正常停止的线程.
  4. 这是指3:您可能会遇到不一致的应用程序状态异常中断线程.

顺便说一句:如果你想指出异常的程序终止,那么返回其他返回代码比0更有意义.

  • "你应该始终完全控制系统状态." 这在Java中是不可能的.IoC框架和应用程序服务器只是您放弃对系统状态控制的两种非常流行和广泛使用的方式.这完全没问题. (2认同)

小智 7

虽然答案确实很有帮助,但有些人错过了一些额外的细节.我希望下面有助于理解java中的关闭过程,除了上面的答案:

  1. 在有序*关闭中,JVM首先启动所有已注册的关闭挂钩.关闭挂钩是使用Runtime.addShutdownHook注册的未启动线程.
  2. JVM不保证启动关闭挂钩的顺序.如果任何应用程序线程(守护程序或非守护程序)仍在关闭时运行,它们将继续与关闭进程同时运行.
  3. 当所有关闭挂钩都已完成时,如果runFinalizersOnExit为true,则JVM可以选择运行终结器,然后停止.
  4. JVM不会尝试停止或中断在关闭时仍在运行的任何应用程序线程; 当JVM最终停止时,它们会突然终止.
  5. 如果关闭挂钩或终结器未完成,则有序关闭进程将"挂起"并且必须突然关闭JVM.
  6. 在突然关闭时,JVM不需要执行除停止JVM之外的任何操作; shutdown hooks不会运行.

PS:JVM可以以有序突然的方式关闭.

  1. 当最后一个"正常"(非守护程序)线程终止,有人调用System.exit或通过其他特定于平台的方法(例如发送SIGINT或按Ctrl-C)时,将启动有序关闭.
  2. 虽然上面是JVM关闭的标准和首选方式,但也可以通过调用Runtime.halt或通过操作系统终止JVM进程(例​​如发送SIGKILL)来突然关闭它.


mfx*_*mfx 5

需要System.exit

  • 当您想要返回非0错误代码时
  • 当你想从不是main()的某个地方退出你的程序时

在您的情况下,它与简单的从主要返回完全相同.