您的位置 首页 java

面试被问什么是Hook钩子线程,没答上来!面试官:回去等通知吧!

正文开始前,分享阿里 P8 资深架构师吐血总结的 《 Java 核心知识体系&面试资料.pdf》

阿里 P8 级资深架构师吐血总结的一份 Java 核心知识.pdf, 内容覆盖很广,Java 核心基础、Java 多线程、高并发、Spring、微服务、Netty 与 RPC、 zookeeper 、Kafka、RabbitMQ、Habase、设计模式、负载均衡、 分布式缓存 、Hadoop、Spark、Storm、云计算等。

获取方式:【 关注 + 转发 】后, 私信 我,回复关键字【 资源 】,即可免费无套路获取哦~

以下是资源的部分目录以及内容截图:

重要的事再说一遍,获取方式:【 关注 + 转发 】后, 私信 我,回复关键字【 资源 】,即可免费无套路获取哦~

目录

  • 一、Hook 线程介绍
  • 二、Hook 线程的应用场景&注意事项
  • 三、Hook 线程防应用重启实战
  • 四、总结

一、Hook 线程介绍

通常情况下,我们可以向应用程序注入一个或多个 Hook (钩子) 线程,这样,在 程序即将退出的时候,也就是 JVM 程序即将退出的时候,Hook 线程就会被启动执行

先看一段示例代码:

  • :为应用程序注入一个钩子(Hook)线程,线程中,打印了相关日志,包括正在运行以及退出的日志;
  • :再次注入一个同样逻辑的钩子(Hook)线程;
  • :主线程执行结束,打印日志;

运行这段代码,来验证一下:

从打印日志看到,当主线程执行结束,也就是 JVM 进程即将退出的时候,注入的两个 Hook 线程都被启动并打印相关日志。

二、Hook 线程的应用场景&注意事项

2.1 应用场景

上面我们已经知道了, Hook 线程能够在 JVM 程序退出的时候被启动且执行,那么,我们能够通过这种特性,做点什么呢?

罗列一些常见应用场景:

  1. 防止程序重复执行 ,具体实现可以在程序启动时,校验是否已经生成 lock 文件,如果已经生成,则退出程序,如果未生成,则生成 lock 文件,程序正常执行,最后再注入 Hook 线程,这样在 JVM 退出的时候,线程中再将 lock 文件删除掉;

  1. Hook 线程中也可以执行一些 资源释放 的操作,比如关闭数据库连接,Socket 连接等。

2.2 注意事项

  1. Hook 线程只有在正确接收到退出信号时,才能被正确执行,如果你是通过 kill-9这种方式,强制杀死的进程,那么抱歉,进程是不会去执行 Hook 线程的,为什么呢?你想啊,它自己都被强制干掉了,哪里还管的上别人呢?
  2. 请不要在 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 文件是否生成:

文件生成成功,接下来,我们再次运行程序,看看是否能够重复启动:

可以看到,无法重复运行程序,且抛出了 Theprogram already running. 的运行时异常。接下来,通过 kill pid 或者 kill-l pid 命令来结束进程:

程序在即将退出的时候,启动了 Hook 线程,在看下 .lock 文件是否已被删除:

到此,Hook 线程代码实战部分结束了。

四、总结

本文中,我们学习了什么是 Hook (钩子) 线程,相关应用场景以及注意事项。祝你学习愉快 !

文章来源:智云一二三科技

文章标题:面试被问什么是Hook钩子线程,没答上来!面试官:回去等通知吧!

文章地址:https://www.zhihuclub.com/188864.shtml

关于作者: 智云科技

热门文章

网站地图