簡(jiǎn)單介紹shutdownHook-Java服務(wù)優(yōu)雅關(guān)閉

背景

在高并發(fā)場(chǎng)景下,服務(wù)發(fā)布或異常退出時(shí),未完成的數(shù)據(jù)處理(如訂單支付、資源釋放)可能導(dǎo)致數(shù)據(jù)不一致。例如:服務(wù)在無(wú)事務(wù)保護(hù)下中斷,會(huì)使部分?jǐn)?shù)據(jù)滯留于中間狀態(tài)(如 “處理中”“鎖定”),需人工介入修復(fù)。為提升系統(tǒng)穩(wěn)定性,引入優(yōu)雅關(guān)閉機(jī)制,確保服務(wù)終止前完成必要的資源清理和數(shù)據(jù)持久化

用法

在Spring中提供了一個(gè)鉤子,當(dāng)jvm收到關(guān)閉通知之后(Kill -15),就會(huì)調(diào)用鉤子中的方法,鉤子中的方法執(zhí)行完成后才會(huì)退出服務(wù)。
服務(wù)啟動(dòng)類中添加,Runtime.getRuntime().addShutdownHook(Thread) 需要傳入一個(gè)線程對(duì)象,后續(xù)動(dòng)作將會(huì)在該異步線程內(nèi)完成
JVM 層面的 ShutdownHook,可直接注冊(cè) JVM 關(guān)閉鉤子:

public class Application {
    public static void main(String[] args) {
        // 注冊(cè)關(guān)閉鉤子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            log.info("Shutdown hook triggered, performing cleanup...");
            try {
                // 資源釋放邏輯(如關(guān)閉連接池)
                databaseClient.close();
                cacheClient.disconnect();
                log.info("Cleanup completed, exiting");
            } catch (Exception e) {
                log.error("Error during shutdown", e);
            }
        }, "shutdown-hook-thread"));

        // 應(yīng)用啟動(dòng)邏輯
        startServer();
    }
}

Spring 框架集成方案
Spring 提供DisposableBean、@PreDestroy和ApplicationListener<ContextClosedEvent>等多種優(yōu)雅關(guān)閉方案

@Component
public class ThreadPoolCollect implements DisposableBean {
    /**
     * 優(yōu)雅關(guān)閉線程池
     */
    @Override
    public void destroy() throws Exception {
        shutdownThreadPool(commonThreadPool, "commonThreadPool");
        shutdownThreadPool(shardMetaThreadPool, "shardMetaThreadPool");
    }
}

除了主動(dòng)關(guān)閉應(yīng)用(使用 kill -15 指令),以下場(chǎng)景也將會(huì)觸發(fā) ShutdownHook :
代碼執(zhí)行結(jié)束,JVM 正常退出
應(yīng)用代碼中調(diào)用 System#exit 方法
應(yīng)用中發(fā)生 OOM 錯(cuò)誤,導(dǎo)致 JVM 關(guān)閉
終端中使用 Ctrl+C(非后臺(tái)運(yùn)行)

原理分析

后面有空再補(bǔ)充。

注意事項(xiàng)

1、ShutdownHook 需要盡快執(zhí)行結(jié)束,比如使用while(true) 會(huì)導(dǎo)致服務(wù)一直沒(méi)辦法倍關(guān)閉;
2、不能使用Kill -9關(guān)閉服務(wù),會(huì)導(dǎo)致不會(huì)調(diào)用shutdownHook;
3、shutdownHook的方法應(yīng)該是線程安全的,因?yàn)榭赡馨l(fā)送信號(hào)導(dǎo)致方法被不同的線程多次調(diào)用;
4、shutdownHook調(diào)用過(guò)程中產(chǎn)生的所有異常都會(huì)被忽略掉;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容