面試官: 說說看, 什麼是 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面試學習資料哦

相關文章
相關標籤/搜索