如果从关机挂钩调用 System.exit,会发生什么情况?

2022-09-04 08:15:09

我在Java中有一个相当复杂的关闭 - 有很多清理工作要做。特别是,我正在尝试弄清楚如何从关闭钩子线程进行错误处理。我的代码目前包括以下内容:

try {
    return shutdownPromise = doShutdown();
}
catch (Throwable exc) {
    logger.error("An exception was thrown while shutting down the application.", exc);  
    System.exit(1);
    return null;
}

当我最初写这篇文章时,我基本上认为,关机中的错误应该直接转到。但水平不是那么低;它调用关机钩子。exitexit

所以我想——

  1. 从关机挂钩调用 exit 有什么作用?
  2. 从关机挂钩处理错误的正确方法是什么?

答案 1

首先,简单的答案是:您的流程死锁。

System.exit 结束调用 ,以以下代码块结尾:Shutdown.exit

synchronized (Shutdown.class) {
     /* Synchronize on the class object, causing any other thread
      * that attempts to initiate shutdown to stall indefinitely
      */
     sequence();
     halt(status);
}

注释是完全准确的。但要理解这一点,我们需要确切地看到关机钩子的作用。

关机钩子是通过 添加的,如此处的答案中所述。请注意,上面的方法最终会在以下代码行中结束:ApplicationShutdownHooks.addsequenceShutdown.runHooks

if (hook != null) hook.run();

首先,请注意,这些挂钩不是应用程序关闭挂钩。它们是不同的系统关闭挂钩,其中一个负责确保应用程序关闭挂钩运行。请注意,这是运行,而不是启动。换句话说,它阻止了。其中一个关闭挂钩将是一个系统挂钩,它同时启动所有应用程序关闭挂钩(您可以自己或在链接的答案中跟踪此代码),然后阻止,直到它们都使用调用完成。其中之一将是您的应用程序关闭钩子 - 如果它调用,它将等待永远打开锁定。Thread.joinSystem.exitShutdown.class

接下来,愚蠢的答案是:打电话代替。我说“愚蠢的答案”,因为这可能是你想要做的稍微低级的事情,而不是退出。如果 表示失败的干净关机,则表示将始终立即成功的硬关机。Runtime.getRuntime().halt()System.exithalt

接下来,更聪明的答案是:可能什么都没有。只需让您的关机挂钩完成,原因如下。您的关机钩子不拥有关机 - 特别是,可能还有其他关机钩子需要完成它们的工作。相反,我怀疑这个钩子的责任之一是最终强制硬关机。我建议立即将其创建为延迟任务,然后正常完成此钩子。


答案 2

推荐