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的加载的…..其实这些都是用到 ...
随机推荐
- 21 shell Here Document/String
Here Document 的用法 Here Document可以将它理解为"嵌入文档""内嵌文档""立即文档",它将命令需要处理的数据或者 ...
- WPF下如何使用TTF字体
之前再写代码的时候如果遇到了图标,我都喜欢再资源文件下创建JPG或者PNG来作为图片. 但是随着TTF字体图标的普及,图标类型的的图片越来越多的被放入到TTF中. 这篇也主要是写再WPF下如何使用TT ...
- Java | 方法的定义 & 重载 & 递归
方法 方法就是一段用来完成特定功能的代码片段. 方法用于定义该类或该类的实例的行为特征和功能实现.方法是类和对象行为特征的抽象.在面向对象中,整个程序的基本单位是类,方法是从属于类和对象的. 方法 ...
- cut和grep 选取命令
cut命令 cut:将一段信息的某一段"切"出来,处理的信息是以行为单位.参数: -d :后接分隔字符,与-f一起使用: -f :依据-d的分隔字符将一段信息切割成为数段,用-f取 ...
- 攻防世界-crypto-Decrypt-the-Message(Poem Codes-诗歌密码)
题目来源:su-ctf-quals-2014题目描述:解密这段信息! 下载附件,内容如下 The life that I have Is all that I have And the life th ...
- Installation failed with message INSTALL_FAILED_TEST_ONLY问题
Android Studio连接手机进行app调试,遇到如下问题: Installation failed with message INSTALL_FAILED_TEST_ONLY. It is p ...
- MapReduce处理简单数据
首先要说明的是,关于老师给的实验要求,我在网上看到了原文,原文地址:https://blog.csdn.net/qq_41035588/article/details/90514824,有兴趣的同学可 ...
- 字符串的模式匹配算法——KMP模式匹配算法
朴素的模式匹配算法(C++) 朴素的模式匹配算法,暴力,容易理解 #include<iostream> using namespace std; int main() { string m ...
- 在Ubuntu20中安装Elasticsearch和Kibana6.8.1版本 母胎教学
首先,我们在Ubuntu中安装Elasticsearch6.8.1命令如下: $ docker pull elasticsearch:6.8.1 拉取完成后,创建Elasticsearch6.8.1容 ...
- JDK的环境变量配置(详细步骤)
JDK环境变量配置的步骤(Windows10) 一.下载并安装JDK 选择一个JDK版本下载并安装到电脑上. 二.环境变量的配置 1.安装完成JDK后的配置环境变量: 首先鼠标右击"计算机& ...