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

时间:2010-09-15 08:39:26

标签: 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? 
    }      
}

document说:“此方法永远不会正常返回。”这是什么意思?

10 个答案:

答案 0 :(得分:195)

在程序退出之前,

System.exit()可用于运行shutdown hooks。这是在较大程序中处理关闭的一种方便方法,其中程序的所有部分都不能(并且不应该)彼此了解。然后,如果有人想要退出,他可以简单地调用System.exit(),并且关闭挂钩(如果正确设置)负责执行所有必要的关机仪式,例如关闭文件,释放资源等。

“此方法永远不会正常返回。”意味着该方法不会返回;一旦一个线程进入那里,就不会再回来了。

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

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

答案 1 :(得分:48)

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

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

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

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

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

答案 2 :(得分:15)

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

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

System.exit(42);

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

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

要了解如何获取退出代码的值并在unix shell脚本或windows cmd脚本中使用它,您可以检查this answer on this site

答案 3 :(得分:14)

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

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

答案 4 :(得分:10)

在可能具有复杂关闭挂钩的应用程序中,不应从未知线程调用此方法。 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();
}

答案 5 :(得分:7)

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

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

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

答案 6 :(得分:6)

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

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

答案 7 :(得分:5)

需要System.exit

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

在你的情况下,它与简单的从主回归完全相同。

答案 8 :(得分:4)

Java Language Specification

  

程序退出

     

程序终止其所有活动,并在两件事之一时退出   发生的情况:

     

所有不是守护程序线程的线程都会终止。

     

某些线程调用Runtime类或类 System 的exit方法,   并且安全管理员不禁止退出操作。

这意味着你应该在拥有大型程序时使用它(好吧,至少比这个程序大)并且想要完成它的执行。

答案 9 :(得分:3)

如果您在JVM中运行了另一个程序并且使用了System.exit,那么第二个程序也将关闭。例如,假设您在群集节点上运行java作业,并且管理群集节点的Java程序在同一JVM中运行。如果作业将使用System.exit,它不仅会退出作业,而且还会关闭整个节点"。由于管理程序被意外关闭,您将无法向该群集节点发送另一个作业。

因此,如果您希望能够从同一JVM中的另一个Java程序控制您的程序,请不要使用System.exit。

如果要故意关闭完整的JVM并且想要利用其他答案中描述的可能性(例如,关闭挂钩:Java shutdown hook,非零,请使用System.exit命令行调用的返回值:How to get the exit status of a Java program in Windows batch file)。

另请参阅运行时异常:System.exit(num) or throw a RuntimeException from main?