91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

java小知識(shí)-ShutdownHook(優(yōu)雅關(guān)閉)

京東云 ? 來(lái)源:京東物流 崔冬冬 ? 作者:京東物流 崔冬冬 ? 2024-12-19 10:36 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

作者:京東物流 崔冬冬

一、先提出一個(gè)問(wèn)題

我們?nèi)绻贘VM退出的時(shí)候做一些事情,比如關(guān)閉遠(yuǎn)程鏈接,怎么實(shí)現(xiàn)呢?

二、ShutdownHook簡(jiǎn)介

java里有個(gè)方法Runtime.getRuntime#addShutdownHook,是否了解呢?

ShutdownHook是什么意思呢,看單詞解釋“關(guān)閉鉤子”,addShutdownHook就是添加一個(gè)關(guān)閉鉤子,這個(gè)鉤子是做什么的呢?能否解決上面的問(wèn)題?

1、RunTime類

先看一下看源碼RunTime#addShutdownHook方法與解釋。

1.1 方法解釋

核心意思,在Java虛擬機(jī)在關(guān)閉時(shí)會(huì)觸發(fā)一些自己添加的事件。

Registers a new virtual-machine shutdown hook.
The Java virtual machine shuts down in response to two kinds of events:
The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
A shutdown hook is simply an initialized but unstarted thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. 
When all the hooks have finished it will then halt. Note that daemon threads will continue to run during the shutdown sequence, as will non-daemon threads if shutdown was initiated by invoking the exit method.

1.2 方法源碼

  public void addShutdownHook(Thread hook) {
        @SuppressWarnings("removal")
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("shutdownHooks"));
        }
        ApplicationShutdownHooks.add(hook);
    }

方法內(nèi)部調(diào)用了ApplicationShutdownHooks#add, 我們繼續(xù)往下看。

2、ApplicationShutdownHooks類

2.1 添加鉤子


     private static IdentityHashMap hooks;
     static synchronized void add(Thread hook) {
        if(hooks == null)
            throw new IllegalStateException("Shutdown in progress");
        if (hook.isAlive())
            throw new IllegalArgumentException("Hook already running");
        if (hooks.containsKey(hook))
            throw new IllegalArgumentException("Hook previously registered");
        hooks.put(hook, hook);
    }

我們添加了一個(gè)鉤子,這個(gè)鉤子是個(gè)線程,這個(gè)線程怎么執(zhí)行的呢? 繼續(xù)看一下此類中的runHooks。

2.2 執(zhí)行鉤子


static void runHooks() {
        Collection threads;
        synchronized(ApplicationShutdownHooks.class) {
            threads = hooks.keySet();
            hooks = null;
        }
        for (Thread hook : threads) {
            hook.start();
        }
        for (Thread hook : threads) {
            while (true) {
                try {
                    hook.join();
                    break;
                } catch (InterruptedException ignored) {
                }
            }
        }
    }

執(zhí)行runHooks的時(shí)候,會(huì)啟動(dòng)所有的hook線程,什么時(shí)候調(diào)用runHooks方法的呢?

2.3 執(zhí)行時(shí)機(jī)

為什么在系統(tǒng)退出的時(shí)候會(huì)執(zhí)行添加的hook呢?我們看一下正常的退出操作System#exit方法。

1) 類調(diào)用層級(jí)

System->Runtime->Shutdown->ApplicationShutdownHooks

2) 方法調(diào)用

系統(tǒng)退出入口:System#exit

步驟 1-->System#exit

步驟 2-->Runtime#exit;

步驟 3--> Shutdown#exit

步驟 4--> Shutdown#runHooks

步驟 5--> ApplicationShutdownHooks#runHooks

步驟 6-->啟動(dòng)添加的hook線程

3) 補(bǔ)充一下

為什么步驟4會(huì)調(diào)用到步驟5呢?

可以看一下ApplicationShutdownHooks的構(gòu)造函數(shù),在創(chuàng)建的時(shí)候,封裝了runHooks方法,放到了Shutdown的鉤子集合里。

如此形成閉環(huán),在系統(tǒng)正常退出的時(shí)候,最終執(zhí)行我們添加的hook。

三、舉個(gè)例子

了解了基本原理,我們看一下怎么使用的

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("等等我");
            }
        };
        Runtime.getRuntime().addShutdownHook(thread);
        System.out.println("程序關(guān)閉"); 
   }
    輸出:
    程序關(guān)閉
    等等我

可以看到,在JVM退出的時(shí)候調(diào)用,執(zhí)行了此線程,我們開(kāi)發(fā)中,哪些場(chǎng)景可以使用呢?

四、應(yīng)用場(chǎng)景

關(guān)閉鏈接、線程、資源釋放、記錄執(zhí)行狀態(tài)等。

五、風(fēng)險(xiǎn)點(diǎn)

1、長(zhǎng)時(shí)間等待

如果添加的hook線程長(zhǎng)時(shí)間執(zhí)行,我們的退出命令會(huì)一直等待,為什么呢?

舉個(gè)例子,我們?cè)趫?zhí)行的時(shí)候sleep一下

  public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000*300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(new Date()+" 等我5分鐘");
            }
        };
        Runtime.getRuntime().addShutdownHook(thread);
        System.out.println(new Date()+" 程序關(guān)閉");
    }
輸出:
Tue Nov 12 17:37:38 CST 2024 程序關(guān)閉
Tue Nov 12 17:42:38 CST 2024 等我5分鐘

2、原因

JVM在退出的時(shí)候會(huì)調(diào)用runHooks方法,看一下上面的方法java.lang.ApplicationShutdownHooks#runHooks方法。

關(guān)鍵字 hook.join(); 主線程會(huì)等待子線程執(zhí)行完成。

如果程序一直執(zhí)行,不能退出怎么辦?

3、解決方案

1 ) 寫(xiě)代碼時(shí)候控制執(zhí)行邏輯、時(shí)長(zhǎng)

kill -9 命令 強(qiáng)制退出

六、擴(kuò)展

1、Runtime.getRuntime#addShutdownHook是面向開(kāi)發(fā)者

ApplicationShutdownHook#add、Shutdown#add我們都不能直接使用。

2、許多中間件框架也利用addShutdownHook來(lái)實(shí)現(xiàn)資源回收、清理等操作

比如Spring框架中,使用了ShutdownHook注冊(cè),我們常用的@PreDestroy在Bean銷毀前執(zhí)行一些操作,也是借助其回調(diào)的。

七、總結(jié)

1、本文簡(jiǎn)單介紹了一下ShutdownHook使用、原理、風(fēng)險(xiǎn)點(diǎn)。

2、我們工作中可以自己注冊(cè)ShutdownHook,主動(dòng)釋放一些資源,降低風(fēng)險(xiǎn)。

3、小知識(shí)分享,不足之處歡迎大家指正,關(guān)于java里的知識(shí)點(diǎn)也歡迎大家討論分享。

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    3001

    瀏覽量

    116419
  • JVM
    JVM
    +關(guān)注

    關(guān)注

    0

    文章

    161

    瀏覽量

    13036
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    freertos關(guān)閉任務(wù)調(diào)度的方法

    #include \"FreeRTOS.h\" #include \"task.h\" /* 關(guān)閉任務(wù)調(diào)度 */ void
    發(fā)表于 11-17 06:47

    電能質(zhì)量在線監(jiān)測(cè)裝置的報(bào)警功能可以關(guān)閉嗎?

    電能質(zhì)量在線監(jiān)測(cè)裝置的報(bào)警功能 能否關(guān)閉及如何關(guān)閉,取決于裝置的設(shè)計(jì)、功能等級(jí)和具體配置 。以下是詳細(xì)分析: 一、核心結(jié)論:報(bào)警功能可部分關(guān)閉,但安全相關(guān)報(bào)警通常不可禁用 多數(shù)裝置支持選擇性關(guān)
    的頭像 發(fā)表于 11-05 13:38 ?418次閱讀

    Arm Neoverse CPU上大代碼量Java應(yīng)用的性能測(cè)試

    Java 是互聯(lián)網(wǎng)領(lǐng)域廣泛使用的編程語(yǔ)言。Java 應(yīng)用的一些特性使其性能表現(xiàn)與提前編譯的原生應(yīng)用(例如 C 程序)大相徑庭。由于 Java 字節(jié)碼無(wú)法直接在 CPU 上執(zhí)行,因此通常運(yùn)行時(shí)在
    的頭像 發(fā)表于 11-05 11:25 ?752次閱讀
    Arm Neoverse CPU上大代碼量<b class='flag-5'>Java</b>應(yīng)用的性能測(cè)試

    交易關(guān)閉自動(dòng)處理接口

    ? ?在電商、支付系統(tǒng)或任何交易密集型應(yīng)用中,交易關(guān)閉(如用戶取消訂單、支付超時(shí)或系統(tǒng)異常)是常見(jiàn)事件。手動(dòng)處理這些事件效率低下且易出錯(cuò),因此開(kāi)發(fā)一個(gè)自動(dòng)處理接口至關(guān)重要。本文將從需求分析、工作原理
    的頭像 發(fā)表于 10-17 14:25 ?435次閱讀
    交易<b class='flag-5'>關(guān)閉</b>自動(dòng)處理接口

    Java效率提升指南:5個(gè)Java工具選型建議及Perforce JRebel和XRebel介紹

    企業(yè)級(jí)Java環(huán)境越來(lái)越復(fù)雜,真正的破局點(diǎn),可能不在“人”,而在于“工具”。5個(gè)實(shí)用建議,幫你理清Java工具的選型思路。
    的頭像 發(fā)表于 09-11 13:59 ?1474次閱讀
    <b class='flag-5'>Java</b>效率提升指南:5個(gè)<b class='flag-5'>Java</b>工具選型建議及Perforce JRebel和XRebel介紹

    Java 在物聯(lián)網(wǎng)與嵌入式系統(tǒng)中的應(yīng)用前景與挑戰(zhàn)

    引言 隨著物聯(lián)網(wǎng)與嵌入式技術(shù)的快速發(fā)展,設(shè)備端的軟件開(kāi)發(fā)需求不斷增加。傳統(tǒng)上,嵌入式設(shè)備多使用 C、C++ 進(jìn)行開(kāi)發(fā),但近年來(lái),Java 逐漸成為物聯(lián)網(wǎng)領(lǐng)域的重要角色。憑借其跨平臺(tái)特性、豐富
    的頭像 發(fā)表于 09-04 14:49 ?987次閱讀

    Perforce JRebel 簡(jiǎn)介:即時(shí)加載代碼變更,加速Java應(yīng)用開(kāi)發(fā)

    Perforce JRebel 專為Java開(kāi)發(fā)提速而生!支持跳過(guò)構(gòu)建與重新部署,實(shí)時(shí)加載代碼變更,支持100+框架,無(wú)縫集成主流IDE與應(yīng)用服務(wù)器。
    的頭像 發(fā)表于 08-14 14:35 ?735次閱讀
    Perforce JRebel 簡(jiǎn)介:即時(shí)加載代碼變更,加速<b class='flag-5'>Java</b>應(yīng)用開(kāi)發(fā)

    A21:分立元件知識(shí)與應(yīng)用專題--電感知識(shí)及應(yīng)用案例

    分立元件知識(shí)與應(yīng)用專題--電感知識(shí)及應(yīng)用案例
    的頭像 發(fā)表于 07-15 19:24 ?450次閱讀
    A21:分立元件<b class='flag-5'>知識(shí)</b>與應(yīng)用專題--電感<b class='flag-5'>知識(shí)</b>及應(yīng)用案例

    A21:分立元件知識(shí)與應(yīng)用專題--電容知識(shí)及應(yīng)用案例

    分立元件知識(shí)與應(yīng)用專題--電容知識(shí)及應(yīng)用案例
    的頭像 發(fā)表于 07-15 19:22 ?454次閱讀
    A21:分立元件<b class='flag-5'>知識(shí)</b>與應(yīng)用專題--電容<b class='flag-5'>知識(shí)</b>及應(yīng)用案例

    EtherCAT運(yùn)動(dòng)控制卡應(yīng)用開(kāi)發(fā)教程之Java

    運(yùn)動(dòng)控制卡的Java開(kāi)發(fā)及DLL調(diào)用
    的頭像 發(fā)表于 06-13 14:29 ?887次閱讀
    EtherCAT運(yùn)動(dòng)控制卡應(yīng)用開(kāi)發(fā)教程之<b class='flag-5'>Java</b>

    Java開(kāi)發(fā)者必備的效率工具——Perforce JRebel是什么?為什么很多Java開(kāi)發(fā)者在用?

    Perforce JRebel是一款Java開(kāi)發(fā)效率工具,旨在幫助java開(kāi)發(fā)人員更快地編寫(xiě)更好的應(yīng)用程序。JRebel可即時(shí)重新加載對(duì)代碼的修改,無(wú)需重啟或重新部署應(yīng)用程序,就能讓開(kāi)發(fā)者即時(shí)看到代碼更改的效果,從而縮短開(kāi)發(fā)、調(diào)試和測(cè)試周期,大大提升開(kāi)發(fā)效率。
    的頭像 發(fā)表于 04-27 13:44 ?842次閱讀
    <b class='flag-5'>Java</b>開(kāi)發(fā)者必備的效率工具——Perforce JRebel是什么?為什么很多<b class='flag-5'>Java</b>開(kāi)發(fā)者在用?

    推薦!如何優(yōu)雅地?cái)[好PCB絲印?

    很多畫(huà)PCB的人,會(huì)認(rèn)為絲印不影響電路的性能,所以,對(duì)絲印并不重視。但是,對(duì)于一個(gè)專業(yè)的硬件工程師來(lái)說(shuō),必須重視這些細(xì)節(jié)。 下面介紹如何優(yōu)雅地弄好PCB絲印。 1 擺放的位置 一般來(lái)說(shuō),電阻、電容
    發(fā)表于 04-08 14:59

    我只會(huì)Java,憑什么不能玩轉(zhuǎn)樹(shù)莓派?GPIO操控竟比C++更優(yōu)雅~

    導(dǎo)語(yǔ)當(dāng)全球開(kāi)發(fā)者默認(rèn)將Python視為樹(shù)莓派的"母語(yǔ)"時(shí),一個(gè)顛覆認(rèn)知的工具鏈正在Java開(kāi)發(fā)者群體中口口相傳——Pi4J讓Java代碼直接操控GPIO、I2C、SPI等硬件接口
    的頭像 發(fā)表于 03-25 09:21 ?1127次閱讀
    我只會(huì)<b class='flag-5'>Java</b>,憑什么不能玩轉(zhuǎn)樹(shù)莓派?GPIO操控竟比C++更<b class='flag-5'>優(yōu)雅</b>~

    恩智浦講解如何在低算力MCU平臺(tái)上優(yōu)雅的計(jì)算均值和方差

    本文主要探討如何在有限的計(jì)算能力和內(nèi)存條件下,優(yōu)雅地實(shí)現(xiàn)高效的均值和方差計(jì)算。通過(guò)優(yōu)化算法、減少計(jì)算復(fù)雜度、利用遞推公式和定點(diǎn)數(shù)運(yùn)算,文章提供了一系列使用技巧,幫忙開(kāi)發(fā)者在保持精度的同時(shí),顯著降低計(jì)算開(kāi)銷。這些方法特別適用于物聯(lián)網(wǎng)設(shè)備、嵌入式系統(tǒng)等對(duì)資源敏感的領(lǐng)域。
    的頭像 發(fā)表于 03-06 08:56 ?1658次閱讀
    恩智浦講解如何在低算力MCU平臺(tái)上<b class='flag-5'>優(yōu)雅</b>的計(jì)算均值和方差

    Java的SPI機(jī)制詳解

    作者:京東物流 楊葦葦 1.SPI簡(jiǎn)介 SPI(Service Provicer Interface)是Java語(yǔ)言提供的一種接口發(fā)現(xiàn)機(jī)制,用來(lái)實(shí)現(xiàn)接口和接口實(shí)現(xiàn)的解耦。簡(jiǎn)單來(lái)說(shuō),就是系統(tǒng)只需要定義
    的頭像 發(fā)表于 03-05 11:35 ?1352次閱讀
    <b class='flag-5'>Java</b>的SPI機(jī)制詳解