JVM钩子函数的使用场景详解

 更新时间:2021年08月22日 16:00:24   作者:Acelin_H  
当jvm进程退出的时候,或者受到了系统的中断信号,hook线程就会启动,一个线程可以注入多个钩,下面这篇文章主要给大家介绍了关于JVM钩子函数使用的相关资料,需要的朋友可以参考下

一、问题引入

背景

在编写一个需要持续在后台运行的程序的时候遇到了这样的场景:我的程序在主函数中创建了一个线程池周期性地执行任务,我希望主线程和线程池都持续运行,但如果收到外部的关闭信号时,主线程和线程池也都能同时退出。想到的就是程序结束的时候需要有一个stop()方法去手动关闭线程池,但是怎么控制这个stop()方法在我想要的时候调用,以什么形式去接收外部的关闭信号也成了需要考虑的问题。

原始思路

最开始的尝试是我将程序的运行和停止分别用"start"和"stop"两种状态表示,然后用一个状态文件state去记录当前的状态(程序启动时默认是"start"),如果想要关闭这个正在运行的程序,就去修改状态文件state,将里面内容变为"stop"。同时在主函数中打开这个状态文件,循环监听里面的内容,如果发现变为"stop",就去调用stop()方法执行关闭逻辑。按照这个思路,我写了一个简单的程序在IDEA中测试了一下效果,发现是可行的。但是当我将程序打包,在mac系统上运行jar包进行测试的时候,不知什么原因,程序总是读到state文件刚打开时的内容,不能检测到state文件的变化,无法按我设想的方式进行关闭。因此只能另想办法。

无意间看见JVM钩子函数的介绍,发现这可能正是我想要的,于是赶紧拿来试一试。

二、JVM钩子使用场景

JVM关闭的情况如下图所示分为三类,第一种是正常的关闭,第二种是异常关闭的情况,第三种是强制关闭的情况。

JVM钩子函数对于前两种方式都可以进行优雅的关闭,但是对最后一种强制关闭就不起作用了。

下面我会根据这三种JVM关闭过程进行简单演示。

正常关闭

代码如下:

public class TestJVMHook {
    public static void main(String[] args) {
        Runtime.getRuntime().addShutdownHook(new Thread(()->
                stop()
        ));
        start();
        System.out.println("===程序正常结束===");
    }
    public static void start() {
        System.out.println("===调用start()方法===");
    }

    public static void stop() {
        System.out.println("===调用stop()方法===");
    }
}

运行结果:

===调用start()方法===
===程序正常结束===
===调用stop()方法===

可以看到,在钩子函数中声明了stop()方法,然后程序正常结束后会自动调用钩子函数。

异常关闭

异常关闭分为OOM和RuntimeException两种情况,我用除数为0的运行时异常来演示。

代码如下:

public class TestJVMHook {
    public static void main(String[] args) {
        Runtime.getRuntime().addShutdownHook(new Thread(()->
                stop()
        ));
        start();
        int res = 10/0;
        System.out.println("===程序结束===");
    }
    public static void start() {
        System.out.println("===调用start()方法===");
    }

    public static void stop() {
        System.out.println("===调用stop()方法===");
    }
}

运行结果:

===调用start()方法===
===调用stop()方法===
Exception in thread "main" java.lang.ArithmeticException: / by zero
 at com.example.TestJVMHook.main(TestJVMHook.java:9)

可以看到执行"10/0"时发生运行时异常,并不会正常打印下一行语句,但仍然会自动调用钩子函数中stop()方法。

强制关闭

这里我们启动一个循环程序,然后手动去关闭它。

代码如下:

public class TestJVMHook {
    public static void main(String[] args) throws InterruptedException {
        Runtime.getRuntime().addShutdownHook(new Thread(()->
                stop()
        ));
        int count = 1;
        start();
        while(true){
            System.out.println("循环计数器"+(count++));
            Thread.sleep(5*1000);
        }
    }
    public static void start() {
        System.out.println("===调用start()方法===");
    }

    public static void stop() {
        System.out.println("===调用stop()方法===");
    }
}

启动后查看进程id,然后通过"kill -9 <pid>"强制关闭:

运行结果:

还是上面那段代码,再次启动,采用"kill <pid>"关闭:

发现通过"kill "正常关闭可以有效调用钩子函数,但是"kill -9 "强制关闭则不会调用钩子函数。

三、回归问题

经过一系列测试,验证了JVM钩子函数确实可以实现我想要的资源关闭效果。由于我的程序是一个循环程序,需要手动关闭,因此可以在关闭程序的脚本中通过kill pid的方式进行钩子函数的调用。

到此这篇关于JVM钩子函数使用场景的文章就介绍到这了,更多相关JVM钩子函数使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Flink实战之实现流式数据去重

    Flink实战之实现流式数据去重

    流式数据是一种源源不断产生的数据,本文探索了一种流式大数据的实时去重方法,不一定适用于所有场景,不过或许可以给面对相似问题的你一点点启发,
    2025-03-03
  • 带你重新认识Java动态代理

    带你重新认识Java动态代理

    这篇文章主要为大家介绍了Java的动态代理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-11-11
  • Mybatis加载策略的实现方法

    Mybatis加载策略的实现方法

    Mybatis中一对一,一对多,多对多关系的配置及实现,可以实现对象的关联查询。实际开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的订单信息,这是就是我们常说的延时加载,本文给大家详细介绍实现方法,一起看看吧
    2022-02-02
  • SpringBoot如何实现文件下载

    SpringBoot如何实现文件下载

    这篇文章主要介绍了SpringBoot如何实现文件下载问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • 基于Java验证jwt token代码实例

    基于Java验证jwt token代码实例

    这篇文章主要介绍了基于Java验证jwt token代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • 详解spring boot配置 ssl

    详解spring boot配置 ssl

    本篇文章主要介绍了详解spring boot配置 ssl,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • java中synchronized锁的升级过程

    java中synchronized锁的升级过程

    这篇文章主要介绍了java中synchronized锁的升级过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • maven 指定version不生效的问题

    maven 指定version不生效的问题

    这篇文章主要介绍了maven 指定version不生效的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • java中String StringBuffer和StringBuilder的区别详解

    java中String StringBuffer和StringBuilder的区别详解

    大家好,本篇文章主要讲的是java中String StringBuffer和StringBuilder的区别详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • MybatisPlus实现数据权限隔离的示例详解

    MybatisPlus实现数据权限隔离的示例详解

    Mybatis Plus对Mybatis做了无侵入的增强,非常的好用,今天就给大家介绍它的其中一个实用功能:数据权限插件,感兴趣的可以跟随小编一起了解下
    2024-04-04

最新评论