前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM关闭前做点什么

JVM关闭前做点什么

作者头像
FunTester
发布2023-09-10 09:42:05
1570
发布2023-09-10 09:42:05
举报
文章被收录于专栏:FunTesterFunTester

今天学到了一个非常有趣的API:java.lang.Runtime#addShutdownHook,顾名思义,就是JVM shutdown的钩子,当JVM关闭时触发的。addShutdownHook 方法是 java.lang.Runtime 类提供的一个方法,用于注册在Java虚拟机即将关闭时执行的代码块(也称为“钩子”或“hook”)。这个代码块会在程序终止之前被执行,无论是正常终止还是由于异常终止。

ShutdownHook介绍

具体来说,addShutdownHook 方法允许你向Java虚拟机注册一个Thread线程,当虚拟机即将关闭时,这个线程会被启动并执行一些清理或其他的操作。

这个方法在以下场景中特别有用:

  1. 资源释放和清理: 当程序退出时,可能需要确保释放资源(如文件、网络连接等)以及做一些清理工作,这样可以避免资源泄漏。
  2. 状态保存: 如果你希望在程序关闭时保存一些状态或数据,可以使用 addShutdownHook 来执行保存操作。
  3. 日志记录: 在程序关闭时记录一些日志,以便后续分析和排查问题。

简单看了一下文档,大概常见3中常见的终止场景都是支持的:

  1. JVM异常终止
  2. 用户主动关闭JVM(ctrl + C、IDE终止功能)
  3. 主动调用System.exit()

值得注意的是,addShutdownHook 注册的代码块在运行时是没有明确定义的执行顺序的,这意味着不能保证它们会按照特定的顺序执行。此外,因为钩子在退出时执行,所以应该避免执行耗时很长的操作,以免影响程序的退出速度。

使用演示

在日常的工作中,经常遇到一个造数据或者清洗大量数据。比如我们有100w个用户,但是符合条件的只有10w个,需要获取用户信息(请求接口)做一个过滤。针对这种场景我常用思路就是开多线程跑,只要有符合条件的用户,就把用户信息存入到一个线程安全的集合,通常是java.util.Vector。最后将这个集合存到文件中。具体代码这里就不演示了,可以参考之前的造数据的文章。

但是在使用过程中难免遇到异常情况:服务不稳定、网络异常、账户异常、缺少校验等等,都会导致运行中断,但是这时候已经有部分用户筛选过了。

这个时候我们添加一个java.lang.Runtime#addShutdownHook钩子,当系统异常中断或者人为手动中断时候,可以将java.util.Vector中保存的有用数据存下来。

演示代码如下:

代码语言:javascript
复制
    public static void main(String[] args) {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println(3)));
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println(32);
            }
        }));
        System.exit(8);
    }

如果使用Groovy的closure封装一层,代码如下:

代码语言:javascript
复制
    /**
     * 添加ShutdownHook
     * @param closure
     * @return
     */
    static def addHook(Closure closure) {
        Runtime.getRuntime().addShutdownHook(new Thread(closure))
    }

然后我突然发现Groovy原声的API就有这个功能:

代码语言:javascript
复制
    /**
     * Allows the usage of addShutdownHook without getting the runtime first.
     *
     * @param self    the object the method is called on (ignored)
     * @param closure the shutdown hook action
     * @since 1.5.0
     */
    public static void addShutdownHook(Object self, Closure closure) {
        Runtime.getRuntime().addShutdownHook(new Thread(closure));
    }

源码发掘

当我再次翻看java.lang.Runtime#addShutdownHook源码时候发现这个钩子是可以多个的,当我们添加带多余1个钩子且JVM关闭时,钩子的执行顺序是不是添加顺序。

Java文档如下:

FunTester原创专题推荐~When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. -- By FunTester

当虚拟机开始关闭时,会运行所有注册过的hook线程,顺序是不确定的,并发运行。so,我们可以注册多个hook。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ShutdownHook介绍
  • 使用演示
  • 源码发掘
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档