JVM 关闭前做点什么
今天学到了一个非常有趣的 API:java.lang.Runtime#addShutdownHook
,顾名思义,就是 JVM shutdown 的钩子,当 JVM 关闭时触发的。addShutdownHook
方法是 java.lang.Runtime
类提供的一个方法,用于注册在 Java 虚拟机即将关闭时执行的代码块(也称为“钩子”或“hook”)。这个代码块会在程序终止之前被执行,无论是正常终止还是由于异常终止。
ShutdownHook 介绍
具体来说,addShutdownHook
方法允许你向 Java 虚拟机注册一个Thread
线程,当虚拟机即将关闭时,这个线程会被启动并执行一些清理或其他的操作。
这个方法在以下场景中特别有用:
资源释放和清理: 当程序退出时,可能需要确保释放资源(如文件、网络连接等)以及做一些清理工作,这样可以避免资源泄漏。
状态保存: 如果你希望在程序关闭时保存一些状态或数据,可以使用
addShutdownHook
来执行保存操作。日志记录: 在程序关闭时记录一些日志,以便后续分析和排查问题。
简单看了一下文档,大概常见 3 中常见的终止场景都是支持的:
JVM 异常终止
用户主动关闭 JVM(ctrl + C、IDE 终止功能)
主动调用
System.exit()
值得注意的是,addShutdownHook
注册的代码块在运行时是没有明确定义的执行顺序的,这意味着不能保证它们会按照特定的顺序执行。此外,因为钩子在退出时执行,所以应该避免执行耗时很长的操作,以免影响程序的退出速度。
使用演示
在日常的工作中,经常遇到一个造数据或者清洗大量数据。比如我们有 100w 个用户,但是符合条件的只有 10w 个,需要获取用户信息(请求接口)做一个过滤。针对这种场景我常用思路就是开多线程跑,只要有符合条件的用户,就把用户信息存入到一个线程安全的集合,通常是java.util.Vector
。最后将这个集合存到文件中。具体代码这里就不演示了,可以参考之前的造数据的文章。
但是在使用过程中难免遇到异常情况:服务不稳定、网络异常、账户异常、缺少校验等等,都会导致运行中断,但是这时候已经有部分用户筛选过了。
这个时候我们添加一个java.lang.Runtime#addShutdownHook
钩子,当系统异常中断或者人为手动中断时候,可以将java.util.Vector
中保存的有用数据存下来。
演示代码如下:
如果使用 Groovy 的closure
封装一层,代码如下:
然后我突然发现 Groovy 原声的 API 就有这个功能:
源码发掘
当我再次翻看java.lang.Runtime#addShutdownHook
源码时候发现这个钩子是可以多个的,当我们添加带多余 1 个钩子且 JVM 关闭时,钩子的执行顺序是不是添加顺序。
Java 文档如下:
When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently.
当虚拟机开始关闭时,会运行所有注册过的 hook 线程,顺序是不确定的,并发运行。so,我们可以注册多个 hook。
版权声明: 本文为 InfoQ 作者【FunTester】的原创文章。
原文链接:【http://xie.infoq.cn/article/34bead7ca000a06b1b0d47448】。文章转载请联系作者。
评论