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