摘要:通過(guò)搜索引擎了解到以下觀點(diǎn)提交到線程池的任務(wù)如果拋出異常會(huì)導(dǎo)致線程掛掉,遂將提交到線程池的任務(wù)中可能出現(xiàn)的異常進(jìn)行了處理,確實(shí)解決了問(wèn)題。
背景
項(xiàng)目中存在一些定時(shí)任務(wù)來(lái)更新數(shù)據(jù)庫(kù)表,借助了線程池提供的一些能力,線上環(huán)境偶爾會(huì)出現(xiàn)網(wǎng)絡(luò)波動(dòng)導(dǎo)致服務(wù)實(shí)例無(wú)法連上數(shù)據(jù)庫(kù),只要出現(xiàn)了這種情況,就會(huì)導(dǎo)致數(shù)據(jù)不會(huì)再被更新,通過(guò)一些命令發(fā)現(xiàn)更新數(shù)據(jù)庫(kù)的線程池中的所有線程都處于waiting狀態(tài)。通過(guò)搜索引擎了解到以下觀點(diǎn):提交到線程池的任務(wù)如果拋出異常會(huì)導(dǎo)致線程掛掉,遂將提交到線程池的任務(wù)中可能出現(xiàn)的異常進(jìn)行了處理,確實(shí)解決了問(wèn)題。
同時(shí)也留下了一個(gè)疑問(wèn):為什么任務(wù)拋出的異常會(huì)導(dǎo)致線程處于waiting狀態(tài)?
本篇文章的關(guān)注點(diǎn)主要集中在ScheduledThreadPoolExecutor.scheduleWithFixedDelay(..)這個(gè)方法上,對(duì)線程池的一些原理性的內(nèi)容以及相關(guān)的術(shù)語(yǔ)不做過(guò)多描述。執(zhí)行流程
scheduleWithFixedDelay(..) 的大體運(yùn)行過(guò)程(注,ScheduledThreadPoolExecutor類中還包含了execute,submit,schedule等方法,這些方法的邏輯基本是一致的):
1、首先對(duì)提交的任務(wù)(Runnable實(shí)例)進(jìn)行一些包裝,生成一個(gè)ScheduledFutureTask:
2、進(jìn)入delayedExecute(..)方法,將生成的ScheduledFutureTask 放到線程池的任務(wù)隊(duì)列(注:BlockingQueue)中;
3、進(jìn)入ensurePrestart()方法,創(chuàng)建Worker實(shí)例開始處理線程:
4、最后就是addWorker方法了,此方法主要關(guān)注以下部分:
到這里,線程池中已經(jīng)創(chuàng)建了線程,并且開始執(zhí)行了。接下來(lái)就看看Worker線程是如何執(zhí)行提交到線程池中的任務(wù)的。
5、上一步中,可以看到Worker中持有的線程已經(jīng)開始運(yùn)行了,而Worker中的線程是這么創(chuàng)建的:
所以,Worker中的線程start之后,則開始執(zhí)行Worker中的run()方法(會(huì)進(jìn)入到runWorker(..)方法)
6、上面的第1、2步中,會(huì)把構(gòu)造的ScheduledFutureTask實(shí)例放到任務(wù)隊(duì)列中,這里會(huì)再?gòu)娜蝿?wù)隊(duì)列中取出該實(shí)例(圖中的while循環(huán)條件),然后再去調(diào)用該實(shí)例的run()方法:
getTask()方法:
7、ScheduledThreadPoolExecutor.ScheduledFutureTask#run()方法:
這里的outerTask就是第1步中的outerTask,其實(shí)就是要執(zhí)行的任務(wù)本身。到了這里給出一個(gè)小結(jié):對(duì)于周期性執(zhí)行的任務(wù),如果該任務(wù)執(zhí)行失敗,則后續(xù)其不會(huì)再被執(zhí)行。
為了內(nèi)容的完整性,下面給出上圖中兩個(gè)方法的流程:
到此,任務(wù)異常導(dǎo)致線程waiting的原因就明了了:
由于任務(wù)執(zhí)行過(guò)程中拋出了異常,會(huì)造成ScheduledFutureTask不會(huì)再將自身放入到任務(wù)隊(duì)列(BlockingQueue)中,即執(zhí)行完之后,任務(wù)隊(duì)列變成了一個(gè)空隊(duì)列,而線程池中的Worker線程會(huì)以阻塞的方式從任務(wù)隊(duì)列中去取任務(wù)(第6步),當(dāng)隊(duì)列為空時(shí),會(huì)導(dǎo)致所有的線程都被阻塞而進(jìn)入waiting狀態(tài)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/77534.html
摘要:結(jié)合之前的線程快照,我發(fā)現(xiàn)這個(gè)消費(fèi)線程也是處于狀態(tài),和后面的業(yè)務(wù)線程池一模一樣。本地模擬本地也是創(chuàng)建了一個(gè)單線程的線程池,分別執(zhí)行了兩個(gè)任務(wù)。發(fā)現(xiàn)當(dāng)任務(wù)中拋出一個(gè)沒(méi)有捕獲的異常時(shí),線程池中的線程就會(huì)處于狀態(tài),同時(shí)所有的堆棧都和生產(chǎn)相符。 showImg(https://segmentfault.com/img/remote/1460000018482477); 背景 事情(事故)是這樣...
摘要:前言前段時(shí)間寫過(guò)一篇線程池沒(méi)你想的那么簡(jiǎn)單,和大家一起擼了一個(gè)基本的線程池,具備線程池基本調(diào)度功能。線程池自動(dòng)擴(kuò)容縮容?;卣{(diào)以上就是線程池的構(gòu)造函數(shù)以及接口的定義。所以我們?cè)谑褂镁€程池時(shí),其中的任務(wù)一定要做好異常處理。線程異常捕獲的重要性。 showImg(https://segmentfault.com/img/remote/1460000019403163?w=1904&h=108...
摘要:死亡狀態(tài)線程退出有可能是正常執(zhí)行完成也有可能遇見異常退出。類有新建與死亡狀態(tài)返回其余狀態(tài)返回判斷線程是否存活。線程因某些原因進(jìn)入阻塞狀態(tài)。執(zhí)行同步代碼塊的過(guò)程中執(zhí)行了當(dāng)前線程放棄開始睡眠進(jìn)入就緒狀態(tài)但是不會(huì)釋放鎖。 【java內(nèi)存模型簡(jiǎn)介 JVM中存在一個(gè)主存區(qū)(Main Memory或Java Heap Memory),Java中所有變量都是存在主存中的,對(duì)于所有線程進(jìn)行共享,而每個(gè)...
摘要:限期阻塞調(diào)用方法等待時(shí)間結(jié)束或線程執(zhí)行完畢。終止?fàn)顟B(tài)線程執(zhí)行完畢或出現(xiàn)異常退了。和都會(huì)檢查線程何時(shí)中斷,并且在發(fā)現(xiàn)中斷時(shí)提前放回。工廠方法將線程池的最大大小設(shè)置為,而將基本大小設(shè)置為,并將超時(shí)大小設(shè)置為分鐘。 wait()、notify()、notifyAll() Object是所有類的基類,它有5個(gè)方法組成了等待、通知機(jī)制的核心:notify()、notifyAll()、wait()...
摘要:死亡狀態(tài)有兩個(gè)原因會(huì)導(dǎo)致線程死亡方法正常退出而自然死亡。一個(gè)未捕獲的異常終止了方法而使線程猝死。注意,放入的線程不必?fù)?dān)心其結(jié)束,超過(guò)不活動(dòng),其會(huì)自動(dòng)被終止。線程間相互干擾描述了當(dāng)多個(gè)線程訪問(wèn)共享數(shù)據(jù)時(shí)可能出現(xiàn)的錯(cuò)誤。 線程 進(jìn)程與線程的區(qū)別 線程是指進(jìn)程內(nèi)的一個(gè)執(zhí)行單元,也是進(jìn)程內(nèi)的可調(diào)度實(shí)體。一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程。 線程的五大狀態(tài) 新建狀態(tài)(New):例如...
閱讀 838·2023-04-25 20:47
閱讀 2604·2019-08-30 15:53
閱讀 1021·2019-08-26 14:05
閱讀 959·2019-08-26 11:59
閱讀 1761·2019-08-26 11:43
閱讀 1788·2019-08-26 10:57
閱讀 1424·2019-08-23 18:23
閱讀 2810·2019-08-23 12:57