温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

JVM钩子函数的使用场景介绍

发布时间:2021-08-22 19:25:07 来源:亿速云 阅读:248 作者:chen 栏目:开发技术

本篇内容主要讲解“JVM钩子函数的使用场景介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JVM钩子函数的使用场景介绍”吧!

目录
  • 一、问题引入

    • 背景

    • 原始思路

  • 二、JVM钩子使用场景

    • 正常关闭

    • 异常关闭

    • 强制关闭

  • 三、回归问题

    一、问题引入

    背景

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

    原始思路

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

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

    二、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>"强制关闭:

    JVM钩子函数的使用场景介绍

    运行结果:

    JVM钩子函数的使用场景介绍

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

    JVM钩子函数的使用场景介绍

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

    三、回归问题

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

    到此,相信大家对“JVM钩子函数的使用场景介绍”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    jvm
    AI