JVM退出收尾机制-JVM Shutdown Hooks

896 阅读2分钟

1. 引言

平时工作中只是关心服务的启动,而很少有人关心服务关闭(JVM退出)。原因是平时很多的业务系统项目基本上不需要关注服务退出。但是对于偏技术的项目就会关注到在服务完全退出前需要做什么工作。今天来介绍一下JVM的 Shutdown Hooks

2.JVM Shutdown

这里以Linux系统上运行JVM为例。JVM shutdown的两种方式:

  • 优雅的shutdown

    • 最后的非守护线程结束
    • 从系统发送信号量,比如:Ctrl+C
    • 代码调用System.exit(), 这种方式在项目启动的时候进行参数判断为通过的情况下
    • kill -15
  • 暴力退出

    • kill -9 这个是最常见的平时开发的过程中使用的命令

    • 代码中调用Runtime.getRuntime().halt()

    • 操作系统崩溃

3. JVM Shutdown Hook

JVM提供了在JVM完全退出之前运行注册函数也就是我们这里说的Shutdown Hook。Shutdown Hook初始化后但是不会运行,那什么时候会运行呢?当JVM开始退出,就会先运行Shutdown Hook。运行完成Shutdown Hook后JVM将会退出。

Tips: 暴力退出是不会运行Shutdown Hook,只有在正常退出才会运行

3.1 如何添加 Shutdown Hook

Thread hook = new Thread(() -> System.out.println(System.currentTimeMillis()));
Runtime.getRuntime().addShutdownHook(hook);

这个就是添加Hook的方式,可以添加多个

Thread hook = new Thread(() -> System.out.println(System.currentTimeMillis()));
Runtime.getRuntime().addShutdownHook(hook);
Thread hook1 = new Thread(() -> System.out.println(System.currentTimeMillis()));
Runtime.getRuntime().addShutdownHook(hook1);

Tips: 多个 Shutdown Hook执行是没有顺序的。

3.2 删除 Shutdown Hook

Thread hook = new Thread(() -> System.out.println(System.currentTimeMillis()));
Runtime.getRuntime().addShutdownHook(hook);
Runtime.getRuntime().removeShutdownHook(hook);

4.Shutdown Hook注意项

JVM退出是没有用户线程后JVM退出,换而言之:JVM中如果有守护线程,JVM还是会退出的。所以:如果增加的Shutdown Hook是做一些持久化的工作或者一些关闭资源的工作正常退出的情况下还必须去做,那么添加的Thread必须是用户线程而非守护线程。

//1 这种情况正常退出hook会执行
Thread hook = new Thread(() -> System.out.println(System.currentTimeMillis()));
Runtime.getRuntime().addShutdownHook(hook);

//2 这种情况正常退出可能不会执行
Thread hook = new Thread(() -> System.out.println(System.currentTimeMillis()));
hook.setDaemon(true);
Runtime.getRuntime().addShutdownHook(hook);

上述代码第一种情况正常退出一定执行,第二种不一定执行。原因就在于第二种情况Hook线程设置成了守护线程。

5. 总结

在了解如何添加JVM Shutdown Hook和Shutdown Hook 线程的一些注意事项后,Shutdown Hook能够用来做一些什么事情:

  • 在JVM正常退出之前需要对内存数据进行持久化(以前可能是定时持久化),这个案例可以研究一下RocketMQ的Broker的源码的内存数据持久化过程
  • 优雅的停机下线-通过设置某个开关来判断是不是继续接收外部的请求。然后进行优雅的停机

我是蚂蚁背大象,文章对你有帮助点赞关注我,文章有不正确的地方请您斧正留言评论~谢谢