如果从关闭钩子调用System.exit会发生什么?

dje*_*lin 11 java shutdown shutdown-hook

我在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;
}
Run Code Online (Sandbox Code Playgroud)

当我最初写这篇文章时,我基本上认为,关机时的错误应该直接进行exit.但是exit水平不是那么低; 它调用了shutdown hooks.

所以我认为 -

  1. 从关闭钩子调用退出做什么?
  2. 从关闭钩子处理错误的正确方法是什么?

dje*_*lin 21

首先,简单的答案是:您的进程死锁.

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);
}
Run Code Online (Sandbox Code Playgroud)

评论完全准确.但要理解这一点,我们需要确切了解关闭钩子的作用.

ApplicationShutdownHooks.add本答案中所述,通过添加关闭挂钩.请注意,sequence上面的方法最终会在以下代码中出现Shutdown.runHooks:

if (hook != null) hook.run();
Run Code Online (Sandbox Code Playgroud)

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

接下来,愚蠢的回答:打电话Runtime.getRuntime().halt()来.我说"愚蠢的答案",因为这可能是你想要做的稍微低一点的事情,而不是退出.如果System.exit代表一个失败的干净关闭,那么halt硬关闭将始终立即成功.

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

  • 我很高兴通过艰难的方式了解到这一点。如果有人感兴趣,这里是案例研究:https://knotgilcup.blogspot.com/2019/08/systemexit-not-working.html (2认同)