一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

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

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

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

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

京東云 ? 來源:京東物流 崔冬冬 ? 作者:京東物流 崔冬冬 ? 2024-12-19 10:36 ? 次閱讀

作者:京東物流 崔冬冬

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

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

二、ShutdownHook簡介

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

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

1、RunTime類

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

1.1 方法解釋

核心意思,在Java虛擬機(jī)在關(guān)閉時(shí)會觸發(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í)候,會啟動(dòng)所有的hook線程,什么時(shí)候調(diào)用runHooks方法的呢?

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

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

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

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會調(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í)行了此線程,我們開發(fā)中,哪些場景可以使用呢?

四、應(yīng)用場景

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

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

1、長時(shí)間等待

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

舉個(gè)例子,我們在執(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í)候會調(diào)用runHooks方法,看一下上面的方法java.lang.ApplicationShutdownHooks#runHooks方法。

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

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

3、解決方案

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

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

六、擴(kuò)展

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

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

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

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

七、總結(jié)

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

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

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

審核編輯 黃宇

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

    關(guān)注

    20

    文章

    2983

    瀏覽量

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

    關(guān)注

    0

    文章

    159

    瀏覽量

    12470
收藏 人收藏

    評論

    相關(guān)推薦

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

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

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

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

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

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

    Java應(yīng)用OOM問題的排查過程

    導(dǎo)讀 本文記錄最近一例Java應(yīng)用OOM問題的排查過程,希望可以給遇到類似問題的同學(xué)提供參考。 前言:此文記錄最近一例Java應(yīng)用OOM問題的排查過程,希望可以給遇到類似問題的同學(xué)提供參考。在本地
    的頭像 發(fā)表于 02-12 11:15 ?456次閱讀
    <b class='flag-5'>Java</b>應(yīng)用OOM問題的排查過程

    Java 23功能介紹

    Java 23 包含全新和更新的 Java 語言功能、核心 API 以及 JVM,同時(shí)適合新的 Java 開發(fā)者和高級開發(fā)者。從?IntelliJ IDEA 2024.2?開始已支持 Java
    的頭像 發(fā)表于 12-04 10:02 ?734次閱讀
    <b class='flag-5'>Java</b> 23功能介紹

    java知識-納秒

    作者:京東物流 崔冬冬 一、System.nanoTime() java中,有這么一個(gè)方法 System.nanoTime() ,你用過嗎? 二、與System.currentTimeMillis
    的頭像 發(fā)表于 11-26 11:11 ?461次閱讀

    Java集合API的改進(jìn)介紹

    解答這些問題。 我們將逐步學(xué)習(xí) Java 集合類的優(yōu)化過程,并按版本逐一對比分析。主要討論的焦點(diǎn)將包括 JDK 1.0、1.2、1.4、1.5、1.6、1.8、9、10、11 和 21 版本的 Java 集合功能 Java 集合
    的頭像 發(fā)表于 11-22 11:12 ?441次閱讀
    <b class='flag-5'>Java</b>集合API的改進(jìn)介紹

    對比Python與Java編程語言

    Python與Java都是目前非常流行的編程語言,它們各有其獨(dú)特的優(yōu)勢和適用場景。以下是對這兩種編程語言的對比: 一、語法和易用性 Python 語法簡潔,代碼更易讀,非常適合初學(xué)者。 動(dòng)態(tài)類型系統(tǒng)
    的頭像 發(fā)表于 11-15 09:31 ?808次閱讀

    基于Java的工具Power Stage Designer

    電子發(fā)燒友網(wǎng)站提供《基于Java的工具Power Stage Designer.pdf》資料免費(fèi)下載
    發(fā)表于 11-14 16:01 ?5次下載
    基于<b class='flag-5'>Java</b>的工具Power Stage Designer

    Java中時(shí)間戳的使用

    Java中時(shí)間戳的使用
    的頭像 發(fā)表于 11-06 16:04 ?411次閱讀
    <b class='flag-5'>Java</b>中時(shí)間戳的使用

    C語言與Java語言的對比

    C語言和Java語言都是當(dāng)前編程領(lǐng)域中的重要成員,它們各自具有獨(dú)特的優(yōu)勢和特點(diǎn),適用于不同的應(yīng)用場景。以下將從語法特性、內(nèi)存管理、跨平臺性、性能、應(yīng)用領(lǐng)域等多個(gè)方面對C語言和Java語言進(jìn)行詳細(xì)對比。
    的頭像 發(fā)表于 10-29 17:31 ?825次閱讀

    java反編譯能拿到源碼嗎

    Java反編譯是一種將編譯后的Java字節(jié)碼(.class文件)轉(zhuǎn)換回Java源代碼的過程。雖然反編譯可以幫助理解代碼的邏輯和結(jié)構(gòu),但它并不總是能完美地還原原始源代碼。反編譯工具通常會產(chǎn)生與原始代碼
    的頭像 發(fā)表于 09-02 11:03 ?1549次閱讀

    【轉(zhuǎn)型必看】Java到AI,程序員的逆襲秘籍,轉(zhuǎn)行人工智能不再是夢!

    人工智能,轉(zhuǎn)型的優(yōu)勢,薪資對比,以及轉(zhuǎn)型所需的知識和學(xué)習(xí)路線等。01Java開發(fā)者能否轉(zhuǎn)型人工智能?答案是肯定的。Java作為一種廣泛使用的編程語言,擁有強(qiáng)大的生
    的頭像 發(fā)表于 07-31 14:42 ?2112次閱讀
    【轉(zhuǎn)型必看】<b class='flag-5'>Java</b>到AI,程序員的逆襲秘籍,轉(zhuǎn)行人工智能不再是夢!

    華納云:java web和java有什么區(qū)別java web和java有什么區(qū)別

    Java Web和Java是兩個(gè)不同的概念,它們在功能、用途和實(shí)現(xiàn)方式上存在一些區(qū)別,下面將詳細(xì)介紹它們之間的區(qū)別。 1. 功能和用途: – Java是一種編程語言,它提供了一種用于開發(fā)各種應(yīng)用程序
    的頭像 發(fā)表于 07-16 13:35 ?1265次閱讀
    華納云:<b class='flag-5'>java</b> web和<b class='flag-5'>java</b>有什么區(qū)別<b class='flag-5'>java</b> web和<b class='flag-5'>java</b>有什么區(qū)別

    華為云開發(fā)者桌面全新發(fā)布 CodeArts IDE for Python,極致優(yōu)雅云原生開發(fā)體驗(yàn)

    Python 編碼體驗(yàn)。 Python 是一種編程語言,廣泛用于 Web 應(yīng)用程序、軟件開發(fā)、數(shù)據(jù)科學(xué)和機(jī)器學(xué)習(xí) (ML)。Python 以其優(yōu)雅的語法、動(dòng)態(tài)解釋性、豐富的標(biāo)準(zhǔn)庫、極高的開發(fā)效率深受全球開發(fā)者
    的頭像 發(fā)表于 05-10 00:27 ?1440次閱讀
    華為云開發(fā)者桌面全新發(fā)布 CodeArts IDE for Python,極致<b class='flag-5'>優(yōu)雅</b>云原生開發(fā)體驗(yàn)