使用線程池時(shí)候當(dāng)程序結(jié)束時(shí)候記得調(diào)用shutdown關(guān)閉線程池

3.10 使用線程池時(shí)候當(dāng)程序結(jié)束時(shí)候記得調(diào)用shutdown關(guān)閉線程池

日常開(kāi)發(fā)中為了便于線程的有效復(fù)用述么,線程池是經(jīng)常會(huì)被用的工具几于,然而線程池使用完后如果不調(diào)用shutdown會(huì)導(dǎo)致線程池資源一直不會(huì)被釋放。下面通過(guò)簡(jiǎn)單例子來(lái)說(shuō)明該問(wèn)題。

3.10.1問(wèn)題復(fù)現(xiàn)

下面通過(guò)一個(gè)例子說(shuō)明當(dāng)不調(diào)用線程池對(duì)象的shutdown方法后圆裕,當(dāng)線程池里面的任務(wù)執(zhí)行完畢后主線程這個(gè)JVM不會(huì)退出。

public class TestShutDown {

        static void asynExecuteOne() {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(new  Runnable() {
            public void run() {
                System.out.println("--async execute one ---");
            }
        });
    }
    
    static void asynExecuteTwo() {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(new  Runnable() {
            public void run() {
                System.out.println("--async execute two ---");
            }
        });
    }
    

    public static void main(String[] args) {
       //(1)同步執(zhí)行
        System.out.println("---sync execute---");
       //(2)異步執(zhí)行操作one
        asynExecuteOne();
       //(3)異步執(zhí)行操作two
        asynExecuteTwo();
       //(4)執(zhí)行完畢
        System.out.println("---execute over---");
    }
}

如上代碼主線程里面首先同步執(zhí)行了操作(1)然后執(zhí)行操作(2)(3)荆几,操作(2)(3)使用線程池的一個(gè)線程執(zhí)行異步操作吓妆,我們期望當(dāng)主線程和操操作(2)(3)執(zhí)行完線程池里面的任務(wù)后整個(gè)JVM就會(huì)退出,但是執(zhí)行結(jié)果卻如下:

image.png

右上角紅色方塊說(shuō)明JVM進(jìn)程還沒(méi)有退出吨铸,Mac上執(zhí)行ps -eaf|grep java后發(fā)現(xiàn)Java進(jìn)程還是存在的行拢,這是什么情況那?修改操作(2)(3)在方法里面添加調(diào)用線程池的shutdown方法如下代碼:

            static void asynExecuteOne() {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(new  Runnable() {
            public void run() {
                System.out.println("--async execute one ---");
            }
        });
        
        executor.shutdown();
    }
    
    static void asynExecuteTwo() {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(new  Runnable() {
            public void run() {
                System.out.println("--async execute two ---");
            }
        });
        
        executor.shutdown();
    }

在執(zhí)行就會(huì)發(fā)現(xiàn)JVM已經(jīng)退出了诞吱,使用ps -eaf|grep java后發(fā)現(xiàn)Java進(jìn)程以及不存在了舟奠,這說(shuō)明只有調(diào)用了線程池的shutdown方法后當(dāng)線程池任務(wù)執(zhí)行完畢后線程池資源才會(huì)釋放。

3.10.2問(wèn)題分析

下面看下為何如此那房维?大家或許還記得基礎(chǔ)篇講解的守護(hù)線程與用戶線程吧沼瘫,JVM退出的條件是當(dāng)前不存在用戶線程,而線程池默認(rèn)的ThreadFactory創(chuàng)建的線程是用戶線程咙俩,

    static class DefaultThreadFactory implements ThreadFactory {
        ...
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

如上代碼可知線程池默認(rèn)的線程工廠創(chuàng)建創(chuàng)建的都是用戶線程耿戚。而線程池里面的核心線程是一直會(huì)存在的湿故,如果沒(méi)有任務(wù)則會(huì)阻塞,所以線程池里面的用戶線程一直會(huì)存在.而shutdown方法的作用就是讓這些核心線程終止膜蛔,下面在簡(jiǎn)單看下shutdown重要代碼:

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            ...
            //設(shè)置線程池狀態(tài)為SHUTDOWN
            advanceRunState(SHUTDOWN);
            //中斷所有的工作線程
            interruptIdleWorkers();
            ...
        } finally {
            mainLock.unlock();
        }
           ...
        }

可知shutdown里面設(shè)置了線程池狀態(tài)為SHUTDOWN坛猪,并且設(shè)置了所有工作線程的中斷標(biāo)志,那么下面在簡(jiǎn)單看下工作線程Worker里面是不是發(fā)現(xiàn)中斷標(biāo)志被設(shè)置了就會(huì)退出了皂股。

  final void runWorker(Worker w) {
            ...
            try {
            while (task != null || (task = getTask()) != null) {
               ...            
            }
            ...
          } finally {
            ...
        }
    }
private Runnable getTask() {
        boolean timedOut = false; 

        for (;;) {
            ...
            //(1)
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }
            
            try {
                //(2)
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

如上代碼正常情況下如果隊(duì)列里面沒(méi)有任務(wù)了墅茉,工作線程阻塞到代碼(2)等待從工工作隊(duì)列里面獲取一個(gè)任務(wù),這時(shí)候如果調(diào)用了線程池的shutdown命令而shutdown命令會(huì)中斷所有工作線程呜呐,所以代碼(2)會(huì)拋出處拋出InterruptedException異常而返回就斤,而這個(gè)異常被catch了,所以繼續(xù)執(zhí)行代碼(1)蘑辑,而shutdown時(shí)候設(shè)置了線程池的狀態(tài)為SHUTDOWN所以getTask方法返回了null战转,所以runWorker方法退出循環(huán),該工作線程就退出了以躯。

3.10.3 總結(jié)

本節(jié)通過(guò)一個(gè)簡(jiǎn)單的使用線程池異步執(zhí)行任務(wù)案例介紹了線程池使用完后要如果不調(diào)用shutdown會(huì)導(dǎo)致線程池的線程資源一直不會(huì)被釋放,然后通過(guò)源碼分析了沒(méi)有被釋放的原因啄踊。所以日常開(kāi)發(fā)中使用線程池的場(chǎng)景一定不要忘記了調(diào)用shutdown方法設(shè)置線程池狀態(tài)和中斷工作線程池

--------------------------------相約GitChat探討技術(shù)--------------------------------------

一忧设、常用開(kāi)源框架 Spring 擴(kuò)展接口揭秘(文章審核中)

評(píng)價(jià)一個(gè)框架是否優(yōu)秀,其中必有一點(diǎn)是看該框架是否留足了可擴(kuò)展的接口颠通。我們?cè)趯?shí)際做項(xiàng)目或者研發(fā)框架時(shí)址晕,很多情況下就是在框架留出的擴(kuò)展接口上進(jìn)行定制,所以很有必要對(duì)這些框架留出了哪些擴(kuò)展點(diǎn)顿锰,這些擴(kuò)展點(diǎn)是干啥用的有個(gè)心知肚明的了解谨垃。

本 Chat 將針對(duì) Spring 擴(kuò)展點(diǎn)進(jìn)行介紹,主要內(nèi)容包括:

  • 對(duì) Spring 框架在容器刷新(Refresh 階段)硼控,創(chuàng)建 Bean(getBean)刘陶,容器銷毀(destory)階段中的擴(kuò)展接口進(jìn)行講解;

  • 對(duì) Spring 中的 ContextLoaderListener 擴(kuò)展接口進(jìn)行講解牢撼,并講解 Webx 框架和 SpringMVC 框架如何使用它匙隔,從而讓 Tomcat 與應(yīng)用框架聯(lián)系起來(lái)。


    image.png
## 二熏版、SpringBoot核心模塊原理分析Chat(文章審核中)

最近微服務(wù)很火纷责,SpringBoot 以其輕量級(jí),內(nèi)嵌 Web 容器撼短,一鍵啟動(dòng)再膳,方便調(diào)試等特點(diǎn)被越來(lái)越多的微服務(wù)實(shí)踐者所采用。然而知其然還要知其所以然曲横,本節(jié)就來(lái)講解 SpringBoot 的核心模塊的實(shí)現(xiàn)原理喂柒,這些內(nèi)容在面試的時(shí)候也是會(huì)被經(jīng)常問(wèn)到的:

  • spring-boot-load 模塊,正常情況下一個(gè)類加載器只能找到加載路徑的jar包里面當(dāng)前目錄或者文件類里面的*.class文件,SpringBoot 允許我們使用 java -jar archive.jar 運(yùn)行包含嵌套依賴 jar 的 jar 或者 war 文件胳喷,那么 SpringBoot 是如何實(shí)現(xiàn)的那湃番?

  • spring-boot-autoconfigure 模塊,Auto-configuration 是 SpringBoot 在 Spring 的基礎(chǔ)上提供的一個(gè)自動(dòng)掃描 jar 包里面指定注解的類并注入到 Spring 容器的功能組件吭露。

  • spring-boot 模塊吠撮,提供了一些特性用來(lái)支持 SpringBoot 中其它模塊。

    歡迎長(zhǎng)按識(shí)別二維碼加入本chat

image.png

三讲竿、Java 類加載器揭秘Chat(文章已經(jīng)出爐)

類加載器作為 JVM 加載字節(jié)碼到內(nèi)存中的媒介泥兰,其重要性不言而喻,另外在職場(chǎng)面試時(shí)候也會(huì)被頻繁的問(wèn)道题禀,了解類加載器的原理鞋诗,能靈活的自定義類加載器去實(shí)現(xiàn)自己的功能顯得尤為重要。

主要內(nèi)容:

  • 講解 Java 中自帶的三種類加載器迈嘹,以及構(gòu)造原理

  • 講解類加載器原理

  • 講解一種特殊的與線程相關(guān)類加載器

  • 講解 Tomcat 框架中多級(jí)類加載器的實(shí)現(xiàn)原理

  • 講解如何自定義類加載器實(shí)現(xiàn)模塊隔離

    歡迎長(zhǎng)按識(shí)別二維碼加入本chat

image

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末削彬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子秀仲,更是在濱河造成了極大的恐慌融痛,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件神僵,死亡現(xiàn)場(chǎng)離奇詭異雁刷,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)保礼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門沛励,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人炮障,你說(shuō)我怎么就攤上這事目派。” “怎么了铝阐?”我有些...
    開(kāi)封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵址貌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我徘键,道長(zhǎng)练对,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任吹害,我火速辦了婚禮螟凭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘它呀。我一直安慰自己螺男,他們只是感情好棒厘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著下隧,像睡著了一般奢人。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淆院,一...
    開(kāi)封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天何乎,我揣著相機(jī)與錄音,去河邊找鬼土辩。 笑死支救,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拷淘。 我是一名探鬼主播各墨,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼启涯!你這毒婦竟也來(lái)了贬堵?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤结洼,失蹤者是張志新(化名)和其女友劉穎扁瓢,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體补君,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年昧互,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挽铁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡敞掘,死狀恐怖叽掘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情玖雁,我是刑警寧澤更扁,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站赫冬,受9級(jí)特大地震影響浓镜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜劲厌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一膛薛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧补鼻,春花似錦哄啄、人聲如沸雅任。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)沪么。三九已至,卻和暖如春锌半,著一層夾襖步出監(jiān)牢的瞬間禽车,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工拳喻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哭当,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓冗澈,卻偏偏與公主長(zhǎng)得像钦勘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子亚亲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345