Java Shutdown Hook使用教程

作者 | 2020年4月23日

在Java中Shutdown Hook机制可以让程序员有机会在JVM退出时执行一些代码,
这个功能在JVM结束时需要执行特殊清理操作的情况下非常有用。

假设我们不使用Shutdown Hook而是使用一般的方法来解决上述问题,例如,我们可以手动地调用某个资源释放函数,但是这类方法某些场景下无法生效:

  • 第一个场景是调用System.exit(0)退出JVM。
  • 第二个场景是通过操作系统终止JVM的进程,例如在Linux下使用kill命令或者在Windows下使用任务管理器杀掉JVM的进程。
  • 第三个场景是由于内存溢出导致的JVM退出。

就像我们即将见到的那样,使用Shutdown Hook可以完美的应对上述几个场景,我们可以通过Shutdown Hook在JVM退出时执行一些代码。

为了使用Shutdown Hook我们需要做的仅仅是实现一个java.lang.Thread类的子类并在该子类中覆写run()方法。然后使用Runtime.getRuntime().addShutdownHook()方法将这个子类注册为Shutdown Hook。如果需要移除一个已注册的Shutdown Hook则可以使用Runtime.getRuntime().removeShutdownHook()方法。

实例

public class ShutDownHook 
{ 
  public static void main(String[] args) 
  { 

    Runtime.getRuntime().addShutdownHook(new Thread() 
    { 
      public void run() 
      { 
        System.out.println("Shutdown Hook is running !"); 
      } 
    }); 
    System.out.println("Application Terminating ..."); 
  } 
} 

当我们运行上面的代码时,你将看到JVM在完成main方法的执行后会调用Shutdown Hook。

输出

Application Terminating ...
Shutdown Hook is running !

使用Shutdown Hook很简单,对吧?

虽然使用Shutdown Hook非常简单,但是需要了解Shutdown Hook的内部原理才能正确使用它们。因此,在本文中,我们将探讨Shutdown Hook设计背后的一些“陷阱”。

1. 某些情况下Shutdown Hook无效

首先要记住的是,无法确保一定会调用Shutdown Hook。如果JVM由于某些内部错误而崩溃,则它可能直接退出而没有机会执行任何指令。

另外如果在Linux下使用kill -9或者在Windows下调用TerminateProcess API来杀掉JVM,这是后JVM的进程会被操作系统立即关闭,也不会调用Shutdown Hook。

在补充一点,通过Runtime.halt()退出JVM也不会调用Shutdown Hook。

当应用程序正常结束时(所有线程运行完成或调用System.exit(0)时)将会调用Shutdown Hook。另外,当JVM由于诸如用户请求终止(Ctrl + C)之类的外部原因而关闭,由操作系统发出的SIGTERM(正常kill命令,不带-9)或操作系统正在关闭时,也会正常调用Shutdown Hook。

2. Shutdown Hook执行到一半JVM就退出了

上面介绍过Shutdown Hook的执行时机,但是可能会发生Shutdown Hook执行到一半时JVM就被强制退出了,例如,用户使用Ctrl + C退出JVM,此时会触发Shutdown Hook执行,然后用户执行强制关机操作。

因此,请让Shutdown Hook的运行时间尽可能短以及避免发生死锁的情况。

3. 可能有多个Shutdown Hook但不保证执行顺序

你可能通过方法名猜到了,方法addShutdownHook()add而不是set,这意味着可以添加多个Shutown Hook,但是JVM并不保证按添加顺序来执行它们。JVM可以按任意顺序执行Shutdown Hook。此外,JVM可能会同时并非执行Shutdown Hook。

4. Shutdown Hook一旦开始运行就不能执行移除/新增操作

一旦JVM开始调用Shutdown Hook,就不允许添加更多或删除任何现有的Shutdown Hook。如果尝试这样做,则JVM会抛出IllegalStateException异常。

5. Shutdown Hook一旦开始运行只能通过Runtime.halt()停止

一旦JVM开始调用Shutdown Hook,只有Runtime.halt()(用于强制终止JVM)可以停止执行Shutdown Hook(除了kill -9与强制关机之类的外部因素)。

6. 使用Shutdown Hook需要的权限

如果我们正在使用Java Security Manager(Java安全管理器),那么执行添加/删除Shutdown Hook的代码在运行时需要具有shutdownHooks权限。

发表评论

电子邮件地址不会被公开。 必填项已用*标注