欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java并發(fā)編程之如何優(yōu)雅關閉鉤子Shutdown Hook

 更新時間:2025年04月29日 15:35:11   作者:寫bug寫bug  
這篇文章主要為大家詳細介紹了Java如何實現優(yōu)雅關閉鉤子Shutdown Hook,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

關閉鉤子簡介

當程序即將退出時(例如釋放資源、關閉數據庫連接等),可以通過預先注冊一個或多個**關閉鉤子線程(Shutdown Hook)**來執(zhí)行相關操作。當 JVM 進程準備退出時,這些鉤子線程會被觸發(fā)并運行。

示例代碼:

public class HookThreadDemo {
    privatestaticclass HookRunnable implements Runnable {
        @Override
        public void run() {
            try {
                System.out.println("鉤子線程 " + Thread.currentThread().getName() + " 正在執(zhí)行...");
                Thread.sleep(2000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("鉤子線程 " + Thread.currentThread().getName() + " 執(zhí)行結束");
        }
    }

    public static void main(String[] args) {
        HookRunnable hookRunnable = new HookRunnable();
        // 添加鉤子線程 0
        Runtime.getRuntime().addShutdownHook(new Thread(hookRunnable));
        // 添加鉤子線程 1
        Runtime.getRuntime().addShutdownHook(new Thread(hookRunnable));
        System.out.println("主線程即將結束執(zhí)行");
    }
}

輸出結果:

主線程即將結束執(zhí)行
鉤子線程 Thread-0 正在執(zhí)行...
鉤子線程 Thread-1 正在執(zhí)行...
鉤子線程 Thread-1 執(zhí)行結束
鉤子線程 Thread-0 執(zhí)行結束

當主線程執(zhí)行完畢后,JVM 進程退出前,所有注冊的鉤子線程會被啟動并執(zhí)行。

關閉鉤子應用場景

釋放資源:關閉文件句柄、數據庫連接等,避免資源泄漏。

停止服務:安全關閉服務器,確保所有請求處理完畢。

發(fā)送通知:通過郵件或短信通知用戶服務已停止。

記錄日志:保存系統(tǒng)狀態(tài)或錯誤信息,便于后續(xù)排查問題。

數據庫連接實戰(zhàn)演示

以下代碼演示如何用關閉鉤子關閉數據庫連接:

public class DatabaseConnection {
    privatestatic Connection conn;

    public static void main(String[] args) {
        System.out.println("主線程開始執(zhí)行");
        initConnection(); // 初始化數據庫連接
        System.out.println("執(zhí)行數據查詢與處理");

        // 注冊關閉鉤子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> closeConnection()));
        System.out.println("主線程結束執(zhí)行");
    }

    private static void initConnection() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/school_info?useSSL=true&",
                "root", "root"
            );
            System.out.println("數據庫連接成功!");
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }

    private static void closeConnection() {
        try {
            conn.close();
            System.out.println("數據庫連接已關閉!");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

輸出結果:

主線程開始執(zhí)行
數據庫連接成功!
執(zhí)行數據查詢與處理
主線程結束執(zhí)行
數據庫連接已關閉!

使用關閉鉤子的注意事項

  • 強制終止進程(如kill -9)不會觸發(fā)鉤子線程。
  • 避免耗時操作:鉤子線程中不要執(zhí)行長時間任務,否則會延遲 JVM 退出。
  • 禁止異常拋出:鉤子線程中的異常可能導致 JVM 無法正常退出。
  • 注冊順序:按依賴關系注冊鉤子,先注冊簡單任務,后注冊復雜任務。
  • 避免啟動新線程:在鉤子中啟動新線程可能導致 JVM 無法正常關閉。

開源框架中的關閉鉤子機制

1. Spring

AbstractApplicationContext中,registerShutdownHook()方法注冊鉤子,用于關閉上下文:

public void registerShutdownHook() {
    if (this.shutdownHook == null) {
        this.shutdownHook = new Thread(() -> doClose());
        Runtime.getRuntime().addShutdownHook(this.shutdownHook);
    }
}

2. Tomcat

Tomcat 通過注冊鉤子確保服務關閉時釋放資源:

public void registerShutdownHook() {
    if (this.shutdownHook == null) {
        this.shutdownHook = new Thread(() -> {
            synchronized (startupShutdownMonitor) {
                doClose();
            }
        });
        Runtime.getRuntime().addShutdownHook(this.shutdownHook);
    }
}

關閉鉤子機制的原理

JVM 啟動時,主線程會創(chuàng)建一個關閉線程(Shutdown Thread),并將所有注冊的鉤子添加到其任務列表中。當 JVM 收到終止信號時:

  • 停止所有用戶線程。
  • 啟動關閉線程,按順序執(zhí)行鉤子任務。
  • 等待所有鉤子執(zhí)行完畢或超時后退出。

鉤子的注冊與執(zhí)行

注冊:通過Runtime.getRuntime().addShutdownHook(Thread)將線程添加到ApplicationShutdownHooks的靜態(tài)列表中。

執(zhí)行:關閉線程按順序同步執(zhí)行系統(tǒng)級鉤子,異步執(zhí)行應用級鉤子,并等待所有線程完成。

關閉鉤子的觸發(fā)時機

  • 主動調用:通過Runtime.exit()System.exit()觸發(fā)。
  • 信號捕獲:JVM 注冊信號處理器(如INT、TERM),捕獲kill命令發(fā)送的信號后觸發(fā)。

示例代碼(捕獲信號):

public class SignalHandlerTest implements SignalHandler {
    public static void main(String[] args) {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> 
            System.out.println("關閉鉤子正在運行...")));

        SignalHandler handler = new SignalHandlerTest();
        Signal.handle(new Signal("INT"), handler);  // 捕獲 Ctrl+C
        Signal.handle(new Signal("TERM"), handler); // 捕獲 kill 命令

        while (true) {
            System.out.println("主線程運行中...");
            Thread.sleep(2000);
        }
    }

    @Override
    public void handle(Signal signal) {
        System.out.println("接收到信號:" + signal.getName() + "-" + signal.getNumber());
        System.exit(0);
    }
}

輸出示例:

主線程運行中...
主線程運行中...
^C接收到信號:INT-2
關閉鉤子正在運行...

信號處理與守護線程

信號不可捕獲的情況KILL(9)和QUIT(3)無法被捕獲。

守護線程:JVM 在所有用戶線程結束后自動退出,守護線程(如 GC 線程)不會阻止 JVM 退出。

總結

Java 的關閉鉤子機制覆蓋了大部分退出場景,但以下情況例外:

  • 使用kill -9強制終止進程時,鉤子不會執(zhí)行。
  • 信號處理需調用System.exit()確保進程退出。

通過合理使用關閉鉤子,可以實現資源釋放、服務優(yōu)雅關閉等關鍵功能。

到此這篇關于Java并發(fā)編程之如何優(yōu)雅關閉鉤子Shutdown Hook的文章就介紹到這了,更多相關Java關閉鉤子內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java通過調用C/C++實現的DLL動態(tài)庫——JNI的方法

    Java通過調用C/C++實現的DLL動態(tài)庫——JNI的方法

    這篇文章主要介紹了Java通過調用C/C++實現的DLL動態(tài)庫——JNI的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2018-01-01
  • Spring排序機制之接口與注解的使用方法

    Spring排序機制之接口與注解的使用方法

    本文介紹了Spring中多種排序機制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了詳細示例,并指導如何選擇合適的排序機制來控制Bean的加載順序和優(yōu)先級,感興趣的朋友一起看看吧
    2025-02-02
  • 深入探討Spring Statemachine在Spring中實現狀態(tài)機的過程

    深入探討Spring Statemachine在Spring中實現狀態(tài)機的過程

    本文深入探討了Spring Statemachine的核心概念、功能及應用,包括狀態(tài)和轉換的結構化定義、事件驅動的狀態(tài)變遷、持久化支持以及集成Spring生態(tài)系統(tǒng),通過實例分析,展示了其在多個領域的實際應用,并討論了如何自定義擴展以滿足特定需求,感興趣的朋友一起看看吧
    2025-04-04
  • Springboot項目中定時任務的四種實現方式詳解

    Springboot項目中定時任務的四種實現方式詳解

    Spring的@Scheduled注解是一種非常簡單和便捷的實現定時任務的方式,通過在方法上添加@Scheduled注解,我們可以指定方法在特定的時間間隔或固定的時間點執(zhí)行,本文給大家介紹Springboot項目中定時任務的四種實現方式,感興趣的的朋友一起看看b
    2024-02-02
  • Spring針對AOP詳細講解

    Spring針對AOP詳細講解

    Spring是一個廣泛應用的框架,SpringAOP則是Spring提供的一個標準易用的aop框架,依托Spring的IOC容器,提供了極強的AOP擴展增強能力,對項目開發(fā)提供了極大地便利
    2022-06-06
  • java 分割csv數據的實例詳解

    java 分割csv數據的實例詳解

    這篇文章主要介紹了java 分割csv數據的實例詳解的相關資料,這里提供了簡單實例,需要的朋友可以參考下
    2017-07-07
  • 深入理解Java中Filter的作用種類及應用場景

    深入理解Java中Filter的作用種類及應用場景

    Filter(過濾器)是Java Web中的一種重要組件,可以對請求和響應進行攔截處理,對數據進行過濾和處理。Filter可以實現許多功能,如:鑒權、日志記錄、字符編碼轉換、數據壓縮、請求重定向等等
    2023-04-04
  • Java中String字符串使用避坑指南

    Java中String字符串使用避坑指南

    Java?中的?String?字符串是我們日常編程中用得最多的類之一,看似簡單的?String?使用,卻隱藏著不少“坑”,如果不注意,可能會導致性能問題、意外的錯誤,今天我們就來聊聊?String?使用中的一些常見坑點,以及如何優(yōu)雅避坑
    2025-04-04
  • 如何使用Spring Security實現用戶-角色-資源的權限控制

    如何使用Spring Security實現用戶-角色-資源的權限控制

    文章介紹了如何通過SpringSecurity實現用戶-角色-資源的權限管理,包括基于角色的請求控制、加載用戶角色信息、角色與資源的關聯(lián)等步驟,同時,提供了一些測試場景,以驗證權限控制是否正確,感興趣的朋友跟隨小編一起看看吧
    2024-10-10
  • spring boot 測試單元修改數據庫不成功的解決

    spring boot 測試單元修改數據庫不成功的解決

    這篇文章主要介紹了spring boot 測試單元修改數據庫不成功的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09

最新評論