面试官: 什么是 Hook (钩子) 线程以及应用场景?

640?wx_fmt=jpeg

目录

  • 一、Hook 线程介绍

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

  • 三、Hook 线程防应用重启实战

  • 四、GitHub 源码地址

  • 五、总结

一、Hook 线程介绍

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

先看一段示例代码:

640?wx_fmt=jpeg

  • :为应用程序注入一个钩子(Hook)线程,线程中,打印了相关日志,包括正在运行以及退出的日志;

  • :再次注入一个同样逻辑的钩子(Hook)线程;

  • :主线程执行结束,打印日志;

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

640?wx_fmt=jpeg

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

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

2.1 应用场景

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

罗列一些常见应用场景:

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

640?wx_fmt=jpeg

PS: 这种防止程序重复执行的策略,也被应用于 Mysql 服务器,zookeeper, kafka 等系统中。

  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();	
    }	
}

运行程序,控制台输出如下:

640?wx_fmt=jpeg

程序一直运行中,再来看下 .lock 文件是否生成:

640?wx_fmt=jpeg

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

640?wx_fmt=jpeg

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

640?wx_fmt=jpeg

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

640?wx_fmt=jpeg

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

四、GitHub 源码地址

https://github.com/weiwosuoai/java-concurrent-tutorial

五、总结

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

六、Ref

  • 《Java 高并发编程详解》

七、赠送面试&学习福利资源

最近在网上发现一个不错的 PDF 资源《Java 核心面试知识.pdf》分享给大家,不光是面试,学习,你都值得拥有!!!

获取方式: 关注本公众号, 后台回复 资源,既可获取资源链接 !!!,下面是目录以及部分截图:

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

重要的事情说两遍,获取方式: 关注本公众号, 后台回复 资源,既可获取资源链接 !!!

·END·

 近期热文:

如果你喜欢本文

请长按二维码,关注小哈学Java

640?wx_fmt=jpeg

转发朋友圈,是对我最大的支持。

看完,赶紧点个“在看”鸭

点鸭点鸭

↓↓↓↓

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值