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