面试官: 说说看, 什么是 Hook (钩子) 线程以及应用场景?
文章首发自个人微信号: 小哈学Java
个人网站地址: https://www.exception.site/java-concurrency/java-concurrency-hook-thread
目录
一、Hook 线程介绍
二、Hook 线程的应用场景&注意事项
三、Hook 线程防应用重启实战
四、GitHub 源码地址
五、总结
一、Hook 线程介绍
通常情况下,我们可以向应用程序注入一个或多个 Hook (钩子) 线程,这样,在程序即将退出的时候,也就是 JVM 程序即将退出的时候,Hook 线程就会被启动执行。
先看一段示例代码:
- ①:为应用程序注入一个钩子(Hook)线程,线程中,打印了相关日志,包括正在运行以及退出的日志;
- ②:再次注入一个同样逻辑的钩子(Hook)线程;
- ③:主线程执行结束,打印日志;
运行这段代码,来验证一下:
从打印日志看到,当主线程执行结束,也就是 JVM 进程即将退出的时候,注入的两个 Hook 线程都被启动并打印相关日志。
二、Hook 线程的应用场景&注意事项
2.1 应用场景
上面我们已经知道了, Hook 线程能够在 JVM 程序退出的时候被启动且执行,那么,我们能够通过这种特性,做点什么呢?
罗列一些常见应用场景:
- 防止程序重复执行,具体实现可以在程序启动时,校验是否已经生成 lock 文件,如果已经生成,则退出程序,如果未生成,则生成 lock 文件,程序正常执行,最后再注入 Hook 线程,这样在 JVM 退出的时候,线程中再将 lock 文件删除掉;
PS: 这种防止程序重复执行的策略,也被应用于 Mysql 服务器,zookeeper, kafka 等系统中。
- Hook 线程中也可以执行一些资源释放的操作,比如关闭数据库连接,Socket 连接等。
2.2 注意事项
- Hook 线程只有在正确接收到退出信号时,才能被正确执行,如果你是通过
kill -9这种方式,强制杀死的进程,那么抱歉,进程是不会去执行 Hook 线程的,为什么呢?你想啊,它自己都被强制干掉了,哪里还管的上别人呢? - 请不要在 Hook 线程中执行一些耗时的操作,这样会导致程序长时间不能退出。
三、Hook 线程防应用重启实战
针对上面防应用重启的场景,利用 Hook 线程,我们来实战一下,贴上代码:
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* @author 犬小哈(微信号: 小哈学Java)
* @date 2019/4/10
* @time 下午9:56
* @discription
**/
public class PreventDuplicated {
/** .lock 文件存放路径 */
private static final String LOCK_FILE_PATH = "./";
/** .lock 文件名称 */
private static final String LOCK_FILE_NAME = ".lock";
public static void main(String[] args) {
// 校验 .lock 文件是否已经存在
checkLockFile();
// 注入 Hook 线程
addShutdownHook();
// 模拟程序一直运行
for (;;) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("The program is running ...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 注入 Hook 线程
*/
private static void addShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// 接受到了退出信号
System.out.println("The program received kill signal.");
// 删除 .lock 文件
deleteLockFile();
}));
}
/**
* 校验 .lock 文件是否已经存在
*/
private static void checkLockFile() {
if (isLockFileExisted()) {
// .lock 文件已存在, 抛出异常, 退出程序
throw new RuntimeException("The program already running.");
}
// 不存在,则创建 .lock 文件
createLockFile();
}
/**
* 创建 .lock 文件
*/
private static void createLockFile() {
File file = new File(LOCK_FILE_PATH + LOCK_FILE_NAME);
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* .lock 文件 是否存在
* @return
*/
private static boolean isLockFileExisted() {
File file = new File(LOCK_FILE_PATH + LOCK_FILE_NAME);
return file.exists();
}
/**
* 删除 .lock 文件
*/
private static void deleteLockFile() {
File file = new File(LOCK_FILE_PATH + LOCK_FILE_NAME);
file.delete();
}
}
运行程序,控制台输出如下:
程序一直运行中,再来看下 .lock 文件是否生成:
文件生成成功,接下来,我们再次运行程序,看看是否能够重复启动:
可以看到,无法重复运行程序,且抛出了 The program already running. 的运行时异常。接下来,通过 kill pid 或者 kill -l pid 命令来结束进程:
程序在即将退出的时候,启动了 Hook 线程,在看下 .lock 文件是否已被删除:
到此,Hook 线程代码实战部分结束了。
四、GitHub 源码地址
https://github.com/weiwosuoai/java-concurrent-tutorial
五、总结
本文中,我们学习了什么是 Hook (钩子) 线程,相关应用场景以及注意事项。祝你学习愉快 !
赠送 | 面试&学习福利资源
获取方式: 关注微信公众号: 小哈学Java, 后台回复"666",既可免费无套路获取资源链接,下面是目录以及部分截图:
欢迎关注微信公众号: 小哈学Java
面试官: 说说看, 什么是 Hook (钩子) 线程以及应用场景?的更多相关文章
- 面试官:“看你简历上写熟悉 Handler 机制,那聊聊 IdleHandler 吧?”
一. 序 Handler 机制算是 Android 基本功,面试常客.但现在面试,多数已经不会直接让你讲讲 Handler 的机制,Looper 是如何循环的,MessageQueue 是如何管理 M ...
- 面试官:看你简历说写精通ThreadLocal,这几道题你都会吗?
问题 和Synchronized的区别 存储在jvm的哪个区域 真的只是当前线程可见吗 会导致内存泄漏么 为什么用Entry数组而不是Entry对象 你学习的开源框架哪些用到了ThreadLocal ...
- 面试官:说说TCP和UDP的区别和应用场景
原创文章首发于公众号:「码农富哥」,欢迎收藏和关注,如转载请注明出处! 上一篇聊完 一文彻底搞懂 TCP三次握手.四次挥手过程及原理 这次聊聊TCP和UDP的区别和场景 TCP/IP 中有两个具有代表 ...
- 面试官的七种武器:Java篇
起源 自己经历过的面试也不少了,互联网的.外企的,都有.总结一下这些面试的经验,发现面试官问的问题其实不外乎几个大类,玩不出太多新鲜玩意的.细细想来,面试官拥有以下七种武器.恰似古龙先生笔下的武侠世界 ...
- 面试官:你对Redis缓存了解吗?面对这11道面试题你是否有很多问号?
前言 关于Redis的知识,总结了一个脑图分享给大家 1.在项目中缓存是如何使用的?为什么要用缓存?缓存使用不当会造成什么后果? 面试官心理分析 这个问题,互联网公司必问,要是一个人连缓存都不太清楚, ...
- 一个HashMap能跟面试官扯上半个小时
一个HashMap能跟面试官扯上半个小时 <安琪拉与面试官二三事>系列文章 一个HashMap能跟面试官扯上半个小时 一个synchronized跟面试官扯了半个小时 一个volatile ...
- Android面试官:说说你对 Binder 驱动的了解?
面试官提了一个问题:说说你对 binder 驱动的了解.这个问题虽有些 "面试造火箭" 的无奈,可难点就是亮点.价值所在,是筛选面试者的有效手段.如果让你回答,你能说出多少呢?我们 ...
- Redis——面试官考题
总结: 本文在一次面试的过程中讲述了 Redis 是什么,Redis 的特点和功能,Redis 缓存的使用,Redis 为什么能这么快,Redis 缓存的淘汰策略,持久化的两种方式,Redis 高可用 ...
- 面试官:我们来聊一聊Redis吧,你了解多少就答多少
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新,建议收藏关注 一.前言 作为一名Java程 ...
随机推荐
- 关于Kafka配额的讨论(1)
Kafka自0.9.0.0版本引入了配额管理(quota management),旨在broker端对clients发送请求进行限流(throttling).目前Kafka支持两大类配额管理: 网络带 ...
- NIO(一)——缓冲区Buffer
NIO(一)--Buffer NIO简介 NIO即New IO,是用来代替标准IO的,提供了与标准IO完全不同传输方式. 核心: ...
- Oracle解锁scott账号
在安装Oracle的最后一步,有一个口令管理的操作,当时忘了给scott账号解锁了(Oracle为程序测试提供的一个普通账户,口令管理中可以对数据库用户设置密码,默认是锁定的).现在想给scott这个 ...
- 【强连通分量】Bzoj1654 [Usaco2006 Jan]The Cow Prom 奶牛舞会
Description 约翰的N(2≤N≤10000)只奶牛非常兴奋,因为这是舞会之夜!她们穿上礼服和新鞋子,别上鲜花,她们要表演圆舞. 只有奶牛才能表演这种圆舞.圆舞需要一些绳索和一个圆形的 ...
- 【线段树】Bzoj1798 [AHOI2009] 维护序列
Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2 ...
- 【Dp】Bzoj1296 [SCOI2009] 粉刷匠
Description windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色. 每个 ...
- BZOJ_1132_[POI2008]Tro_计算几何
BZOJ_1132_[POI2008]Tro_计算几何 Description 平面上有N个点. 求出所有以这N个点为顶点的三角形的面积和 N<=3000 Input 第一行给出数字N,N在[3 ...
- BZOJ_4320_ShangHai2006 Homework_分块
BZOJ_4320_ShangHai2006 Homework_分块 Description 1:在人物集合 S 中加入一个新的程序员,其代号为 X,保证 X 在当前集合中不存在. 2:在当 ...
- 【爆料】-《伯明翰大学学院毕业证书》UCB一模一样原件
☞伯明翰大学学院毕业证书[微/Q:865121257◆WeChat:CC6669834]UC毕业证书/联系人Alice[查看点击百度快照查看][留信网学历认证&博士&硕士&海归 ...
- APP测试要点—UI、功能测试
一.UI测试 测试用户界面(如菜单.对话框.窗口和其它可规控件)布局.风格是否满足客户要求.文字是否正确.页面是否美观.文字.图片组合是否完美.操作是否友好等. UI测试的目标是确保用户界面会通过测试 ...