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 的方式进行钩子函数的调用。
JVM钩子函数的使用的更多相关文章
- java 关闭钩子函数的应用
Runtime.getRuntime().addShutdownHook(shutdownHook); 说明:这个方法的意思就是在jvm中增加一个关闭的钩子,当jvm关闭的时候,会执行系统中已经设置的 ...
- Vue2.X的路由管理记录之 钩子函数(切割流水线)
$route可以在子组件任何地方调用,代表当前路由对象,这个属性是只读的,里面的属性是 immutable(不可变) 的,不过你可以 watch(监测变化) 它. 导航和钩子函数: 导航:路由正在发生 ...
- 【Mocha.js 101】钩子函数
前情提要 在上一篇文章<[Mocha.js 101]同步.异步与 Promise>中,我们学会了如何对同步方法.异步回调方法以及 Promise 进行测试. 在本篇文章中,我们将了解到 M ...
- wordpress钩子和钩子函数
ccc,看了很多博客,无法理解,还是自己来写吧. wordpress 在wordpress中有很多钩子,还有很多钩子函数,在什么地方用什么钩子,用什么钩子函数, 需要明白两个问题: 1:什么是钩子,钩 ...
- 使用PreTranslateMessage替代钩子函数处理键盘消息
2002年左右,我所在公司在开发基于H.323的VoIP电话系统(用了以色列一家公司的库,具体名字忘记了). 去电信科技研究院测试系统,同事发现处理键盘消息总有一些莫名其妙的问题,比如延迟或异常. 我 ...
- 10.PHP内核探索:Apache运行与钩子函数
Apache是目前世界上使用最为广泛的一种Web Server,它以跨平台.高效和稳定而闻名.按照去年官方统计的数据,Apache服务器的装机量占该市场60%以上的份额.尤其是在 X(Unix/Lin ...
- 对于数据包的截取,使用linux中的netfilter钩子函数
http://blog.csdn.net/wswifth/article/details/5115358 在师哥的代码(packet.c)中使用的是Linux2.4内核中的一个子系统:netfilte ...
- 黄聪:WordPress动作钩子函数add_action()、do_action()源码解析
WordPress常用两种钩子,过滤钩子和动作钩子.过滤钩子相关函数及源码分析在上篇文章中完成,本篇主要分析动作钩子源码. 然而,在了解了动作钩子的源码后你会发现,动作钩子核心代码竟然跟过滤钩子差不多 ...
- 利用钩子函数来捕捉键盘响应的windows应用程序
一:引言: 你也许一直对金山词霸的屏幕抓词的实现原理感到困惑,你也许希望将你的键盘,鼠标的活动适时的记录下来,甚至你想知道木马在windows操作系统是怎样进行木马dll的加载的…..其实这些都是用到 ...
随机推荐
- 8 shell if else
if 语句的判断条件,从本质上讲,判断的就是命令的退出状态. 语句 语句格式 同一行书写 注意点 用例1 用例2 if 语句 if conditionthen statement(s)fi if ...
- NodeJS 进程是如何退出的
有几种因素可以导致 NodeJS 进程退出.在这些因素中,有些是可预防的,比如代码抛出了一个异常:有些是不可预防的,比如内存耗尽.process 这个全局变量是一个 Event Emitter 实例, ...
- nmon打开nmon文件出现 运行时错误13类型不匹配问题解决
根据nmon工具安装及nmon analyser的使用 - 空谷幽兰LDD - 博客园 (cnblogs.com)文中,用nmon_analyse去打开监控到的nmon文件,出几个报错. 1 用WPS ...
- Blazor 数据绑定开发指南
翻译自 Waqas Anwar 2021年3月21日的文章 <A Developer's Guide to Blazor Data Binding> [1] 现如今,大多数 Web 应用程 ...
- Emoji.voto,Linkerd 服务网格(service mesh)的示例应用程序
一个微服务应用程序,允许用户为他们最喜欢的表情符号(emoji)投票,并跟踪排行榜上收到的投票.愿最好的 emoji 获胜. 该应用程序由以下 3 个服务组成: emojivoto-web:Web 前 ...
- LeetCode 895. Maximum Frequency Stack
题目链接:https://leetcode.com/problems/maximum-frequency-stack/ 题意:实现一种数据结构FreqStack,FreqStack需要实现两个功能: ...
- linux服务器安装svn超详细介绍
#!/bin/sh REPOS="$1" REV="$2" export LANG=en_US.UTF-8 LOG_PATH=/tmp/svn.log echo ...
- 自动化测试(1)selenium+python+chrome 连接测试
环境准备: python版本:3.8.4 开发工具:pycharm 使用chrome和对应的webdriver http://npm.taobao.org/mirrors/chromedriver/ ...
- Python基础之分离文件名和文件路径
参考链接:https://blog.csdn.net/qq_42110481/article/details/81104182 分离文件名与文件路径: import os if __name__ == ...
- 为什么 WordPress 镜像用起来顺手?
有用户朋友问,用已有WordPress镜像好?还是自己动手安装配置好? 答案:用Websoft9的相关镜像好(各大云市场的镜像提供商比较多,"真假李逵"的现象总是有的,我们只对We ...