在很多实际应用环境中,当用户关闭了应用程序的时候,需要做一些善后的清理工作。但是问题是用户有时候并不会按照推荐的方法关闭应用程序,更有可能不做清理工作。例如,在windows系统中,你打开了某个软件,那么软件开发商推荐退出软件的方式是在软件图标上右键退出或者在软件窗口上左键关闭,但是会有很多用户在实际操作中可能是打开任务管理器直接关闭进程,这样来达到关闭软件的目的。在这种情况中有可能会发生一些意外情况。
幸运的是Java为程序员提供了一种优雅的方法可以在关闭过程中执行一些代码,这样就能确保那些负责善后处理的代码能够执行。
在Java中,虚拟机会对两类事件进行响应,然后执行关闭操作:- 当调用`System.exit()`方法或者程序的最后一个非守护线程退出的时候,应用程序正常退出。
- 当用户突然强制停止虚拟机的时候,例如`Ctrl+C`。
幸运的是虚拟机在执行关闭操作的时候会经历以下两个阶段
- 如果有的话,虚拟机启动所有已经注册的关闭钩子。关闭钩子是之前通过Runtime类注册的线程,所有的关闭钩子会并发执行,一直到完成任务。
- 虚拟机根据情况调用所有没有被调用过的终结器(finalizer)。
我们今天重点讨论第一个阶段。
我们查看下在JDK文档中`Runtime`类的说明。public class Runtimeextends Object每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。 应用程序不能创建自己的 Runtime 类实例。 void addShutdownHook(Thread hook) 注册新的虚拟机来关闭钩子。
测试Demo
/** * 测试 shutdownhook */ public class ShutdownHookTest { public static void main(String[] args) { try { Runtime.getRuntime().addShutdownHook(new MyHook()); System.out.println(Thread.currentThread().getName() + "准备睡眠 1秒"); Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + "线程睡眠完毕,线程退出"); } catch (Exception e) { e.printStackTrace(); } } static class MyHook extends Thread { @Override public void run() { System.out.println("my shutdown hook run"); } } }
运行结果:
main准备睡眠 1秒main线程睡眠完毕,线程退出my shutdown hook run