Java虚拟机关闭钩子(ShutdownHook)

2022-03-10 22:25栏目:编程
TAG:

Shutdown Hooks 是一种特殊的结构,它允许开发人员插入 JVM 关闭时执行的一段代码。

用途

Application 正常退出(所有线程完成时,或在调用 System.exit(0) 时),执行特定的业务逻辑或关闭资源等操作。

Application 非正常退出(用户按下 Ctrl+C、操作系统关闭(kill pid,不带-9)),在退出时执行必要的挽救措施。

用法

示例:

1public class ShutDownHook { 2    public static void main(String[] args) { 3 4        Runtime.getRuntime() 5               .addShutdownHook(new Thread(() -> System.out.println("Shutdown Hook is running !"))); 6        System.out.println("Application Terminating ..."); 7    } 8}

输出:

1Application Terminating ... 2Shutdown Hook is running !

可以看到 Shutdown Hook is running ! 输出在 Application Terminating ... 之后。

陷阱

在某些情况下,可能无法执行 Shutdown Hook。

如果 JVM 由于某些内部错误而崩溃,则它可能崩溃而没有机会执行一条指令。另外,如果操作系统发出 SIGKILL 信号(在 Unix/Linux 中为 kill -9)或 TerminateProcess(Windows),则要求应用程序立即终止而无需甚至在等待任何清理活动。除上述内容外,还可以通过调用 Runtime.halt() 方法来终止 JVM,而不允许运行 Shutdown Hook。

启动后,可以在完成之前强行关闭 Shutdown Hook。

在诸如操作系统关闭之类的情况下,有可能在 Shutdown Hook 完成之前将其终止。在这种情况下,一旦给出 SIGTERM,O/S 将等待进程终止指定的时间。如果该过程未在此期限内终止,则操作系统将通过发出SIGTERM(或Windows中的对应程序)来强制终止该过程。因此,当关闭 Shutdown Hook 执行到一半时,可能会发生这种情况。

因此,建议确保 Shutdown Hook 的谨慎书写,以确保它们快速完成,并且不会引起死锁等情况。另外,JavaDoc 特别提到不应在 Shutdown Hook 中执行长时间计算或等待用户 I/O 操作。

可以有多个 Shutdown Hook,但是不能保证它们的执行顺序。

可以注册多个 Shutdown Hook,但是 JVM 无法保证其执行顺序(shutdownHooks 存放在 IdentityHashMap 中),JVM 可以按任意顺序执行关闭 Shutdown Hook,也可能会同时执行 Shutdown Hooks。

1public void addShutdownHook(Thread hook) { 2    SecurityManager sm = System.getSecurityManager(); 3    if (sm != null) { 4        sm.checkPermission(new RuntimePermission("shutdownHooks")); 5    } 6    ApplicationShutdownHooks.add(hook); 7} 8 9class ApplicationShutdownHooks { 10    /* The set of registered hooks */ 11    private static IdentityHashMap<Thread, Thread> hooks; 12    static synchronized void add(Thread hook) { 13        if(hooks == null) 14            throw new IllegalStateException("Shutdown in progress"); 15 16        if (hook.isAlive()) 17            throw new IllegalArgumentException("Hook already running"); 18 19        if (hooks.containsKey(hook)) 20            throw new IllegalArgumentException("Hook previously registered"); 21 22        hooks.put(hook, hook); 23    } 24}

关闭程序开始后,无法注册/取消注册 Shutdown Hook。

一旦关闭程序是由 JVM 发起的,将不在允许添加或删除任何现有的 Shutdown Hook,否则抛出 IllegalStateException 异常。

关闭程序开始后,只能由 Runtime.halt() 停止。

一旦关闭程序开始,只有 Runtime.halt()(强制终止 JVM)可以停止执行关闭序列(除了诸如 SIGKILL 之类的外部影响之外)。这意味着在 Shutdown Hook 中调用 System.exit() 将不起作用。实际上,如果在 Shutdown Hook 中调用 System.exit(),VM 可能会卡住,我们可能不得不强制终止该过程。

使用 Shutdown Hook 需要安全权限。

如果我们使用的是 Java Security Manager,则执行添加/删除 Shutdown Hook 的代码在运行时需要具有 shutdownHooks 权限。如果我们在安全的环境中未经许可调用此方法,则将导致 SecurityException。

本文来自网络,不代表山斋月平台立场,转载请注明出处: https://www.shanzhaiyue.top