ScheduledThreadPoolExecutor源碼解析

ScheduledThreadPoolExecutor主要用來定期執(zhí)行任務(wù)沛厨,或者是在給定的延遲之后運行任務(wù)吨拗。它的功能與Timer類似,但是比起Timer恕刘,ScheduledThreadPoolExecutor功能更強(qiáng)大鹃锈,使用也更靈活攀例。

ScheduledThreadPoolExecutor與Timer區(qū)別:

  • Timer對應(yīng)單個后臺線程振坚,所有的任務(wù)都由同一個線程調(diào)度购撼,因此所有的任務(wù)都是串行執(zhí)行的,前一個任務(wù)的延遲或者異常都將會影響到之后的任務(wù)匕累;

  • ScheduledThreadPoolExecutor對應(yīng)多個后臺線程陵刹,每一個調(diào)度的任務(wù)都將由線程池中的一個線程去執(zhí)行,在同一時刻欢嘿,任務(wù)并發(fā)執(zhí)行衰琐,并且它們之間不會相互干擾。

ScheduledThreadPoolExecutor源碼分析

在開始分析源碼具體實現(xiàn)之前际插,先給一個簡單的ScheduledThreadPoolExecutor使用案例:


ScheduledThreadPoolExecutor使用案例
  1. ScheduledThreadPoolExecutor聲明;

  2. 調(diào)用scheduleAtFixedRate方法和scheduleWithFixedDelay方法提交定時任務(wù)task显设。

類聲明

在看構(gòu)造方法之前先來看看ScheduledThreadPoolExecutor類聲明:


ScheduledThreadPoolExecutor類聲明

從ScheduledThreadPoolExecutor類聲明可以看出:

  • ScheduledThreadPoolExecutor是ThreadPoolExecutor的子類框弛,并且實現(xiàn)了接口ScheduledExecutorService;

  • ScheduledThreadPoolExecutor是另外一種線程池捕捂,它同ThreadPoolExecutor擁有相同的特性瑟枫,但是又略有不同,具體的不同之處會在后文做詳細(xì)的介紹指攒。

構(gòu)造方法

ScheduledThreadPoolExecutor提供3個構(gòu)造方法以供使用者使用:


構(gòu)造方法

從構(gòu)造方法可以看出慷妙,ScheduledThreadPoolExecutor使用DelayQueue來作為線程池的工作隊列,由于DelayQueue是無界隊列允悦,根據(jù)線程池的工作原理膝擂,核心參數(shù)maximumPoolSize在ScheduledThreadPoolExecutor中是沒有什么意義的。

總的來說隙弛,ScheduledThreadPoolExecutor為了實現(xiàn)周期性執(zhí)行任務(wù)架馋,對ThreadPoolExecutor做了以下改動:

  • 工作隊列使用DelayQueue;

  • 任務(wù)提交之后統(tǒng)統(tǒng)都進(jìn)工作隊列全闷;

  • 獲取任務(wù)的方式改變叉寂,執(zhí)行了任務(wù)之后,也增加了額外的處理总珠,具體的改變后文會一一給出詳細(xì)的分析屏鳍。

任務(wù)提交與調(diào)度

ScheduledThreadPoolExecutor中最常用的任務(wù)提交的方法有兩個:ScheduleAtFixedRate方法和ScheduleWithFixedDelay方法。


源碼實現(xiàn)

具體的執(zhí)行流程如下:

  1. 參數(shù)校驗局服,不合法參數(shù)拋出異常钓瞭;

  2. 構(gòu)造task;

  3. 調(diào)用delayedExecute方法進(jìn)行后續(xù)相關(guān)處理淫奔。

接下來我們先來分析ScheduledThreadPoolExecutor的調(diào)度任務(wù)的最小單位ScheduledFutureTask相關(guān)實現(xiàn)降淮。

ScheduledFutureTask

  • 成員變量
    ScheduledFutureTask包含3個成員變量:


    成員變量
    1. sequenceNumber:任務(wù)被添加到ScheduledThreadPoolExecutor中的序號;

    2. time:任務(wù)將要被執(zhí)行的具體時間;

    3. period:任務(wù)執(zhí)行的間隔周期佳鳖。

    ScheduledThreadPoolExecutor會把待執(zhí)行的任務(wù)放到工作隊列DelayQueue中霍殴,DelayQueue封裝了一個PriorityQueue,PriorityQueue會對隊列中的ScheduledFutureTask進(jìn)行排序系吩,具體的排序算法實現(xiàn)如下:

  • compareTo實現(xiàn)


    compareTo實現(xiàn)
    • 首先按照time排序来庭,time小的排在前面,time大的排在后面穿挨;

    • 如果time相同月弛,按照sequenceNumber排序,sequenceNumber小的排在前面科盛,sequenceNumber大的排在后面帽衙,換句話說,如果兩個task的執(zhí)行時間相同贞绵,優(yōu)先執(zhí)行先提交的task厉萝。

  • 任務(wù)調(diào)度之run方法實現(xiàn)
    run方法是調(diào)度task的核心,task的執(zhí)行實際上是run方法的執(zhí)行榨崩。


    run方法實現(xiàn)

    具體執(zhí)行流程如下:

    • 步驟1:判斷當(dāng)前task是否可以執(zhí)行谴垫,如果不能執(zhí)行,調(diào)用cancel方法取消task執(zhí)行母蛛,否則翩剪,跳轉(zhuǎn)到步驟2;

    • 步驟2:判斷當(dāng)前task是否到達(dá)執(zhí)行時間點彩郊,如果到達(dá)前弯,執(zhí)行該task,否則跳轉(zhuǎn)到步驟3秫逝;

    • 步驟3:重置狀態(tài)博杖,計算任務(wù)下次執(zhí)行時間,重新把任務(wù)添加到工作隊列中筷登,讓該任務(wù)可重復(fù)執(zhí)行剃根。

看完task之后,我們接下看看看構(gòu)造好task之后的delayedExecute方法相關(guān)實現(xiàn)前方。

** delayedExecute實現(xiàn)**


delayedExecute實現(xiàn)

delayedExecute方法主要完成了這些操作:

  1. 將task添加到工作隊列狈醉;

  2. 調(diào)用ensurePrestart()方法做預(yù)處理,該方法實現(xiàn)在線程池一文中做過詳細(xì)分析在這里就不再做贅述了惠险。

任務(wù)調(diào)度小結(jié)

到這里為止苗傅,ScheduledThreadPoolExecutor的task執(zhí)行過程可以總結(jié)為下圖:


任務(wù)執(zhí)行步驟
  • 步驟1:線程1從工作隊列DelayQueue中獲取已到期的task;
  • 步驟2:線程1執(zhí)行該task班巩;
  • 步驟3:線程1修改ScheduledFutureTask的time變量為下次被執(zhí)行的時間渣慕;
  • 步驟4:線程1將修改后的task重新放回DelayQueue中嘶炭。

接下來我們來詳細(xì)看看各個步驟DelayQueue具體相關(guān)實現(xiàn)。

任務(wù)獲取 - take實現(xiàn)

take實現(xiàn)

具體執(zhí)行步驟如下:

  1. 獲取Lock逊桦;

  2. 從優(yōu)先隊列中獲取任務(wù):

  • 步驟1:如果PriorityQueue為空眨猎,當(dāng)前線程到Condition中等待,否則執(zhí)行步驟2强经;

  • 步驟2:如果PriorityQueue的第一個元素的時間比當(dāng)前時間小睡陪,獲取該任務(wù),否則匿情,線程到Condition中等待兰迫;

  • 步驟3:獲取任務(wù)成功后,如果PriorityQueue不為空炬称,喚醒等待在Condition中的所有線程汁果。

  1. 釋放Lock。

ScheduledThreadPoolExecutor的getTask()方法會無限循環(huán)獲取task玲躯,直到線程從PriorityQueue中獲取到一個元素后据德,才會退出無限循環(huán)。

任務(wù)添加 - add實現(xiàn)

add實現(xiàn)

add方法的核心是offer方法調(diào)用府蔗,我們來看看offer方法的具體實現(xiàn):
offer實現(xiàn)

具體執(zhí)行步驟如下:

  1. 獲取Lock晋控;

  2. 添加任務(wù):

  • 向PriorityQueue添加任務(wù)汞窗;

  • 如果待添加的任務(wù)是PriorityQueue的第一個元素姓赤,喚醒在Condition中等待的所有線程。

  1. 釋放Lock仲吏。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末不铆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子裹唆,更是在濱河造成了極大的恐慌誓斥,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件许帐,死亡現(xiàn)場離奇詭異劳坑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)成畦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門距芬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人循帐,你說我怎么就攤上這事框仔。” “怎么了拄养?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵离斩,是天一觀的道長。 經(jīng)常有香客問我,道長跛梗,這世上最難降的妖魔是什么寻馏? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮茄袖,結(jié)果婚禮上操软,老公的妹妹穿的比我還像新娘。我一直安慰自己宪祥,他們只是感情好聂薪,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蝗羊,像睡著了一般藏澳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耀找,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天翔悠,我揣著相機(jī)與錄音,去河邊找鬼野芒。 笑死蓄愁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的狞悲。 我是一名探鬼主播撮抓,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼摇锋!你這毒婦竟也來了丹拯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤荸恕,失蹤者是張志新(化名)和其女友劉穎乖酬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體融求,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡咬像,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了生宛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片县昂。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖茅糜,靈堂內(nèi)的尸體忽然破棺而出七芭,到底是詐尸還是另有隱情,我是刑警寧澤蔑赘,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布狸驳,位于F島的核電站预明,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏耙箍。R本人自食惡果不足惜撰糠,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辩昆。 院中可真熱鬧阅酪,春花似錦、人聲如沸汁针。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽施无。三九已至辉词,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間猾骡,已是汗流浹背瑞躺。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留兴想,地道東北人幢哨。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像嫂便,于是被迫代替她去往敵國和親捞镰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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