如何優(yōu)雅的關(guān)閉Java線程池

原文:https://www.cnblogs.com/qingquanzi/p/9018627.html

本篇就以ThreadPoolExecutor為例届宠,來介紹下如何優(yōu)雅的關(guān)閉線程池圃泡。

01 線程中斷

在介紹線程池關(guān)閉之前撬槽,先介紹下Thread的interrupt逾一。

在程序中侦铜,我們是不能隨便中斷一個線程的先鱼,因為這是極其不安全的操作辟躏,我們無法知道這個線程正運行在什么狀態(tài)君纫,它可能持有某把鎖驯遇,強行中斷可能導(dǎo)致鎖不能釋放的問題;或者線程可能在操作數(shù)據(jù)庫蓄髓,強行中斷導(dǎo)致數(shù)據(jù)不一致混亂的問題叉庐。正因此,JAVA里將Thread的stop方法設(shè)置為過時会喝,以禁止大家使用陡叠。

一個線程什么時候可以退出呢?當然只有線程自己才能知道肢执。

所以我們這里要說的Thread的interrrupt方法枉阵,本質(zhì)不是用來中斷一個線程。是將線程設(shè)置一個中斷狀態(tài)预茄。

當我們調(diào)用線程的interrupt方法兴溜,它有兩個作用:

1、如果此線程處于阻塞狀態(tài)(比如調(diào)用了wait方法耻陕,io等待)拙徽,則會立馬退出阻塞,并拋出InterruptedException異常淮蜈,線程就可以通過捕獲InterruptedException來做一定的處理斋攀,然后讓線程退出。

2梧田、如果此線程正處于運行之中淳蔼,則線程不受任何影響侧蘸,繼續(xù)運行,僅僅是線程的中斷標記被設(shè)置為true鹉梨。所以線程要在適當?shù)奈恢猛ㄟ^調(diào)用isInterrupted方法來查看自己是否被中斷讳癌,并做退出操作。

注:

如果線程的interrupt方法先被調(diào)用存皂,然后線程調(diào)用阻塞方法進入阻塞狀態(tài)晌坤,InterruptedException異常依舊會拋出。

如果線程捕獲InterruptedException異常后旦袋,繼續(xù)調(diào)用阻塞方法骤菠,將不再觸發(fā)InterruptedException異常。

02 線程池的關(guān)閉

線程池提供了兩個關(guān)閉方法疤孕,shutdownNow和shuwdown方法商乎。

shutdownNow方法的解釋是:線程池拒接收新提交的任務(wù),同時立馬關(guān)閉線程池祭阀,線程池里的任務(wù)不再執(zhí)行鹉戚。

shutdown方法的解釋是:線程池拒接收新提交的任務(wù),同時等待線程池里的任務(wù)執(zhí)行完畢后關(guān)閉線程池专控。

以上的說法雖然沒錯抹凳,但是還有很多的細節(jié),比如調(diào)用shutdown方法后伦腐,正在執(zhí)行任務(wù)的線程做出什么反應(yīng)赢底?正在等待任務(wù)的線程又做出什么反應(yīng)?線程在什么情況下才會徹底退出蔗牡。如果不了解這些細節(jié)颖系,在關(guān)閉線程池時就難免遇到,像線程池關(guān)閉不了辩越,關(guān)閉線程池出現(xiàn)報錯等情況嘁扼。

再說這些關(guān)閉線程池細節(jié)之前,需要強調(diào)一點的是黔攒,調(diào)用完shutdownNow和shuwdown方法后趁啸,并不代表線程池已經(jīng)完成關(guān)閉操作,它只是異步的通知線程池進行關(guān)閉處理督惰。如果要同步等待線程池徹底關(guān)閉后才繼續(xù)往下執(zhí)行不傅,需要調(diào)用awaitTermination方法進行同步等待。

有了以上介紹赏胚,下面就結(jié)合線程池源碼访娶,分別說說這兩個線程池關(guān)閉方法的一些實現(xiàn)細節(jié)。

shutdownNow

我們看一下shutdownNow方法的源碼:

image

在shutdownNow方法里觉阅,重要的三句代碼我用紅色數(shù)字標出來了崖疤。

第一句就是原子性的修改線程池的狀態(tài)為STOP狀態(tài)(比較簡單我就不貼代碼了)

第三句是將隊列里還沒有執(zhí)行的任務(wù)放到列表里秘车,返回給調(diào)用方。

第二句是遍歷線程池里的所有工作線程劫哼,然后調(diào)用線程的interrupt方法叮趴。如下圖:

image

以上就是shutdownNow方法的執(zhí)行邏輯:將線程池狀態(tài)修改為STOP,然后調(diào)用線程池里的所有線程的interrupt方法权烧。

調(diào)用shutdownNow后眯亦,線程池里的線程會做如何反應(yīng)呢?那就要看般码,線程池里線程正在執(zhí)行的代碼邏輯了妻率。其在線程池的runWorker方法里(對線程池的執(zhí)行原理不了解的,請看之前的文章)侈询,其代碼如下:

image

正常情況下舌涨,線程池里的線程,就是在這個while循環(huán)里不停地執(zhí)行扔字。其中代碼task.run()就是在執(zhí)行我們提交給線程池的任務(wù),如當我們調(diào)用shutdownNow時温技,task.run()里面正處于IO阻塞革为,則會導(dǎo)致報錯,如果task.run()里正在正常執(zhí)行舵鳞,則不受影響震檩,繼續(xù)執(zhí)行完這個任務(wù)。

從上圖看的出來蜓堕,如果getTask()方法返回null,也會導(dǎo)致線程的退出抛虏。我們再來看看getTask方法的實現(xiàn):

image

如果我們調(diào)用shutdownNow方法時,線程處于從隊列里讀取任務(wù)而阻塞中(圖中下邊的紅框)套才,則會導(dǎo)致拋出InterruptedException異常迂猴,但因為異常被捕獲,線程將會繼續(xù)在這個for循環(huán)里執(zhí)行背伴。

還記得shutdownNow方法里將線程修改為STOP狀態(tài)吧沸毁,當執(zhí)行到上邊紅框里的代碼時,由于STOP狀態(tài)值是大于SHUTDOWN狀態(tài)傻寂,STOP也大于等于STOP息尺,不管任務(wù)隊列是否為空,都會進入if語句從而返回null,線程退出疾掰。

總結(jié):

當我們調(diào)用線程池的shutdownNow時搂誉,

如果線程正在getTask方法中執(zhí)行,則會通過for循環(huán)進入到if語句静檬,于是getTask返回null,從而線程退出炭懊。不管線程池里是否有未完成的任務(wù)并级。

如果線程因為執(zhí)行提交到線程池里的任務(wù)而處于阻塞狀態(tài),則會導(dǎo)致報錯(如果任務(wù)里沒有捕獲InterruptedException異常)凛虽,否則線程會執(zhí)行完當前任務(wù)死遭,然后通過getTask方法返回為null來退出。

shutdown

我們再來看看shutdown方法的源碼:

image

跟shutdownNow類似凯旋,只不過它是將線程池的狀態(tài)修改為SHUTDOWN狀態(tài)呀潭,然后調(diào)用interruptIdleWorkers方法,來中斷空閑的線程至非。這是interruptIdleWorkers方法的實現(xiàn):

image

跟shutdownNow方法調(diào)用interruptWorkers方法不同的是钠署,interruptIdleWorkers方法在遍歷線程池里的線程時,有一個w.tryLock()加鎖判斷荒椭,只有加鎖成功的線程才會被調(diào)用interrupt方法谐鼎。那什么情況下才能被加鎖成功?什么情況下不能被加鎖成功呢?這就需要我們繼續(xù)回到線程執(zhí)行的runWorker方法趣惠。

在上邊runWorker方法代碼的截圖中狸棍,我刻意將w.lock()和w.unlock()調(diào)用用紅框圈起。其實就是正運行在w.lock和w.unlock之間的線程將因為加鎖失敗味悄,而不會被調(diào)用interrupt方法草戈,換句話說,就是正在執(zhí)行線程池里任務(wù)的線程不會被中斷侍瑟。

不管是被調(diào)用了interrupt的線程還是沒被調(diào)用的線程唐片,什么時候退出呢?涨颜,這就要看getTask方法的返回是否為null了费韭。

在getTask里的if判斷(上文中g(shù)etTask代碼截圖中上邊紅色方框的代碼)中,由于線程池被shutdown方法修改為SHUTDOWN狀態(tài)庭瑰,SHUTDOWN大于等于SHUTDOWN成立沒問題星持,但是SHUTDOWN不在大于等于STOP狀態(tài),所以只有隊列為空见擦,getTask方法才會返回null钉汗,導(dǎo)致線程退出。

總結(jié):

當我們調(diào)用線程池的shuwdown方法時鲤屡,

如果線程正在執(zhí)行線程池里的任務(wù)损痰,即便任務(wù)處于阻塞狀態(tài),線程也不會被中斷酒来,而是繼續(xù)執(zhí)行卢未。

如果線程池阻塞等待從隊列里讀取任務(wù),則會被喚醒,但是會繼續(xù)判斷隊列是否為空辽社,如果不為空會繼續(xù)從隊列里讀取任務(wù)伟墙,為空則線程退出。

03 優(yōu)雅的關(guān)閉線程池

有了上邊對兩個關(guān)閉線程池方法的了解滴铅,相信優(yōu)雅安全關(guān)閉線程池將不再是問題戳葵。

我們知道,使用shutdownNow方法汉匙,可能會引起報錯拱烁,使用shutdown方法可能會導(dǎo)致線程關(guān)閉不了。

所以當我們使用shutdownNow方法關(guān)閉線程池時噩翠,一定要對任務(wù)里進行異常捕獲戏自。

當我們使用shuwdown方法關(guān)閉線程池時,一定要確保任務(wù)里不會有永久阻塞等待的邏輯伤锚,否則線程池就關(guān)閉不了擅笔。

最后,一定要記得屯援,shutdownNow和shuwdown調(diào)用完猛们,線程池并不是立馬就關(guān)閉了,要想等待線程池關(guān)閉狞洋,還需調(diào)用awaitTermination方法來阻塞等待阅懦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市徘铝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惯吕,老刑警劉巖惕它,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異废登,居然都是意外死亡淹魄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門堡距,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甲锡,“玉大人,你說我怎么就攤上這事羽戒$吐伲” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵易稠,是天一觀的道長缸废。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么企量? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任测萎,我火速辦了婚禮,結(jié)果婚禮上届巩,老公的妹妹穿的比我還像新娘硅瞧。我一直安慰自己,他們只是感情好恕汇,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布腕唧。 她就那樣靜靜地躺著,像睡著了一般拇勃。 火紅的嫁衣襯著肌膚如雪四苇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天方咆,我揣著相機與錄音月腋,去河邊找鬼。 笑死瓣赂,一個胖子當著我的面吹牛榆骚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播煌集,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼妓肢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了苫纤?” 一聲冷哼從身側(cè)響起碉钠,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卷拘,沒想到半個月后喊废,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡栗弟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年污筷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乍赫。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡瓣蛀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出雷厂,到底是詐尸還是另有隱情惋增,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布罗侯,位于F島的核電站器腋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜纫塌,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一诊县、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧措左,春花似錦依痊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至凉逛,卻和暖如春性宏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背状飞。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工毫胜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诬辈。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓酵使,卻偏偏與公主長得像,于是被迫代替她去往敵國和親焙糟。 傳聞我的和親對象是個殘疾皇子口渔,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容