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

Hook 钩子线程

文章首发自我的微信号: 小哈学Javajava

我的网站地址: https://www.exception.site/java-concurrency/java-concurrency-hook-threadgit

目录

  • 1、Hook 线程介绍github

  • 2、Hook 线程的应用场景&注意事项面试

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

  • 4、GitHub 源码地址数据库

  • 5、总结服务器

1、Hook 线程介绍

一般状况下,咱们能够向应用程序注入一个或多个 Hook (钩子) 线程,这样,在程序即将退出的时候,也就是 JVM 程序即将退出的时候,Hook 线程就会被启动执行微信

先看一段示例代码:学习

示例代码

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

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

Hook 线程执行结果

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

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

2.1 应用场景

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

罗列一些常见应用场景:

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

流程图

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

  1. Hook 线程中也能够执行一些资源释放的操做,好比关闭数据库链接,Socket 链接等。

2.2 注意事项

  1. Hook 线程只有在正确接收到退出信号时,才能被正确执行,若是你是经过 kill -9这种方式,强制杀死的进程,那么抱歉,进程是不会去执行 Hook 线程的,为何呢?你想啊,它本身都被强制干掉了,哪里还管的上别人呢?
  2. 请不要在 Hook 线程中执行一些耗时的操做,这样会致使程序长时间不能退出。

3、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 文件是否生成:

lock 文件

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

重复启动程序,抛出异常

能够看到,没法重复运行程序,且抛出了 The program already running. 的运行时异常。接下来,经过 kill pid 或者 kill -l pid 命令来结束进程:

Hook 线程被启动了

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

.lock 文件被删除了

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

4、GitHub 源码地址

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

5、总结

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

赠送 | 面试&学习福利资源

获取方式: 关注微信公众号: 小哈学Java, 后台回复"666",既可免费无套路获取资源连接,下面是目录以及部分截图:

关注微信公众号【小哈学Java】,回复“666”,便可免费无套路领取哦

欢迎关注微信公众号: 小哈学Java

小哈学Java,关注领取10G面试学习资料哦

相关文章
相关标签/搜索