首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2EE

Java 應用程式優雅關機:Shutdown Hook 完整實作指南

     編輯:J2EE

為什麼需要 Shutdown Hook?

多執行緒應用中,主執行緒結束或 System.exit() 被呼叫時,JVM 會啟動關機序列。若無掛鉤,資料庫連線池、執行緒池、暫存檔、記憶體快取等資源可能來不及釋放,導致資料不一致或資源洩漏。

核心 API

Runtime.getRuntime().addShutdownHook(Thread hook)
  • 可註冊多個 Hook,JVM 關機時 並行啟動 所有 Hook 執行緒。
  • Hook 應為 守護執行緒 或短時間完成,避免阻塞關機過久(JVM 無強制超時,但 OS 可能強殺)。
  • removeShutdownHook 可移除已註冊 Hook。
  • Runtime.halt() 會 不執行 Hook 直接終止。

完整範本

public class GracefulShutdown {
    private static final Logger LOG = LoggerFactory.getLogger(GracefulShutdown.class);

    public static void main(String[] args) {
        // 1. 註冊關機鉤子(盡早註冊)
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            LOG.info("=== 應用程式關機序列啟動 ===");
            try {
                // 2. 關閉資源:資料庫連線池、HTTP Client、執行緒池、MQ 連線...
                DataSourcePool.shutdown();      // 例:HikariCP.shutdown()
                ThreadPoolManager.shutdown();   // 例:executor.shutdown() + awaitTermination
                CacheManager.persistToDisk();   // 熱資料落盤
                TempFileCleaner.cleanup();      // 刪除暫存檔
                LOG.info("所有資源已釋放");
            } catch (Exception e) {
                LOG.error("關機過程發生錯誤", e);
            }
        }, "Shutdown-Hook"));

        // 3. 主程式邏輯
        Application app = new Application();
        app.start(); // 內部可能啟動 Web Server、排程器等
    }
}

Spring Boot 整合

Spring 容器關機時自動呼叫 DisposableBean.destroy()、@PreDestroy、SmartLifecycle.stop(),無需手寫 Hook。若需補充:

@Component
public class CustomShutdownHook {
    @Autowired DataSource dataSource;
    @Autowired ThreadPoolTaskExecutor taskExecutor;

    @PreDestroy
    public void onShutdown() {
        if (dataSource instanceof HikariDataSource) ((HikariDataSource)dataSource).close();
        taskExecutor.shutdown();
    }
}

注意事項與最佳實務

  1. 冪等性:Hook 可能被重複觸發(極少見),關閉操作需冪等。
  2. 順序:先停止接受新請求 → 等待在途請求完成 → 關閉下游連線 → 釋放本地資源。
  3. 超時保護:使用 CountDownLatch 或 CompletableFuture 等待關鍵步驟,設定最大等待時間。
  4. 測試:單元測試模擬 System.exit(0) 驗證 Hook 邏輯;整合測試用 kill -TERM 驗證容器層面關機。

常見誤區

  • ❌ 在 Hook 中啟動新非守護執行緒 → JVM 永不退出。
  • ❌ Hook 執行耗時過長(> 分鐘) → 容器強制殺掉,資源釋放不完整。
  • ❌ 依賴 finalize() 釋放資源 → 不可靠、已淘汰。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved