文章首發自我的微信號: 小哈學Javajava
我的網站地址: https://www.exception.site/java-concurrency/java-concurrency-hook-threadgit
1、Hook 線程介紹github
2、Hook 線程的應用場景&注意事項面試
3、Hook 線程防應用重啓實戰sql
4、GitHub 源碼地址數據庫
5、總結服務器
一般狀況下,咱們能夠嚮應用程序注入一個或多個 Hook (鉤子) 線程,這樣,在程序即將退出的時候,也就是 JVM 程序即將退出的時候,Hook 線程就會被啓動執行。微信
先看一段示例代碼:學習
運行這段代碼,來驗證一下:網站
從打印日誌看到,當主線程執行結束,也就是 JVM 進程即將退出的時候,注入的兩個 Hook 線程都被啓動並打印相關日誌。
上面咱們已經知道了, Hook 線程可以在 JVM 程序退出的時候被啓動且執行,那麼,咱們可以經過這種特性,作點什麼呢?
羅列一些常見應用場景:
PS: 這種防止程序重複執行的策略,也被應用於 Mysql 服務器,zookeeper, kafka 等系統中。
kill -9
這種方式,強制殺死的進程,那麼抱歉,進程是不會去執行 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 線程代碼實戰部分結束了。
https://github.com/weiwosuoai/java-concurrent-tutorial
本文中,咱們學習了什麼是 Hook (鉤子) 線程,相關應用場景以及注意事項。祝你學習愉快 !
獲取方式: 關注微信公衆號: 小哈學Java, 後臺回覆"666",既可免費無套路獲取資源連接,下面是目錄以及部分截圖: