【多線程】線程池源碼(2)

時隔上一篇技術文章更新差不多有3個星期了窗宇,原因的話在上一篇文章中寫啦。廢話不多說瞳浦,開始我們的線程池源碼的第二輪閱讀担映。

回顧

簡單回顧下上一篇線程池源碼中涉及的兩個方法废士,一個是execute() 執(zhí)行任務的入口叫潦,還有一個是addWorker() 最通俗地理解就是是否需要添加新線程。而在addWoker() 的末尾有這樣一段代碼

if (workerAdded) {
    t.start();
    workerStarted = true;
}

明顯地看到這里通過start() 方法開啟了多線程官硝,而如果想要看線程的執(zhí)行邏輯矗蕊,就需要去到對應類中查看run方法短蜕,這里的t就是Worker 類里面的一個成員變量,所以重點要看Worker 類中的run() 方法傻咖。

runWorker()

run() 方法的源碼如圖所示朋魔,最后是到了runWorker()

image

直接來看runWorker的源碼

image
  1. 開始是一個循環(huán),要么執(zhí)行worker自帶的第一個任務(firstTask)卿操,要么通過getTask() 獲取任務
  2. 有任務首先得保證線程池是正常的警检,以下兩種情況均調用wt.interrupt()線程設置中斷標志位
    1. 線程池處于STOP狀態(tài),也就是不接受新任務害淤,也不執(zhí)行隊列中的任務
    2. 如果線程的標志位已經為true扇雕,那么清楚標志位,此時的線程池狀態(tài)為STOP狀態(tài)窥摄,這里看起來可能比較別扭镶奉,有了第一種情況為什么還要第二種,不理解的可以先略過崭放,后面會講的哨苛。
  3. 正常情況下是調用beforeExecute()afterExecute() 包裹者task.run()

看一下是如何自定義前置和后置執(zhí)行邏輯

由于是換電腦寫了,所以例子可能和前一篇文章的不完全一樣币砂,但是表達的是同一個意思

public class ThreadPoolExamples {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new MyThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());

        MyThread myThread = new MyThread();
        executor.execute(myThread);

    }
}


class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " is running");
    }
}

class MyThreadPoolExecutor extends ThreadPoolExecutor {
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        System.out.println("【" + Thread.currentThread().getName() + " custom before execute】");
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        System.out.println("【" + Thread.currentThread().getName() + " is done】");
    }

    MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }
}

首先就是要創(chuàng)建自己的MyThreadPoolExecutor 類建峭,繼承ThreadPoolExecutor ,然后重寫beforeExecute()afterExecute() 定義自己的邏輯即可道伟,看下測試結果

image

可以看到前置和后置都已經按照既定的邏輯在運行了迹缀,有趣的是,22分鐘過去了(不要問我為什么這么久蜜徽,拿外賣吃東西去了)線程池還是沒有停祝懂,為什么會這樣呢。

注意前面分析runWorker() 第一步的時候是一個循環(huán)拘鞋,然后通過firstTask 或者getTask() 獲取任務砚蓬,如果兩種方式都獲取不到任務,線程池就應該退出盆色,看來奧秘在getTask() 中灰蛙。

getTask()

主要目的顧名思義就是獲取到需要執(zhí)行的任務,直接看源碼

image
  1. 一進來也是一個死循環(huán)隔躲,可以先聚焦什么時候會退出循環(huán)摩梧,肯定是不正常的情況下會退出
    1. 當線程池狀態(tài)不處于RUNNING或者SHUTDOWN的時候,或者是當線程處于SHUTDOWN但是工作隊列中沒有任務
    2. 當wc大于最大線程數并且工作隊列為空的時候宣旱,或者當wc大于核心線程數并且timedOut為true并且核心隊列為空的時候仅父,或者如果設置了allowCoreThreadTimeOut,并且wc > 1或者核心隊列為空的時候
  2. 除了不正常的情況,接下來就是從工作隊列中獲取任務笙纤,不過是根據timed的來決定是用poll() 還是take() 耗溜。
  3. 如果能取出任務,就直接返回任務省容;如果沒有任務抖拴,要么超時設置timedOut為ture,要么是拋出異常重置timedOut為false腥椒。

可以看到阿宅,只有上述不正常的情況下退出循環(huán),任務返回null笼蛛,進而導致runWorker() 中的while循環(huán)退出家夺,最后整個線程池關閉。否則都是會一直在getTask() 這里死循環(huán)伐弹。

到這里拉馋,為什么說線程池能夠節(jié)省資源呢,是因為其實它創(chuàng)建的線程的消耗只是體現在了Worker類的創(chuàng)建中惨好,把其它要完成的任務放在工作隊列里面煌茴,然后getTask() 獲取任務,最后執(zhí)行任務(調用task.run())

拒絕策略

這個是在最開始execute() 的時候調用的

image

詳細是如何請看下面的動圖

image

可以看到日川,最后是調用了RejectedExecutionHandler 接口中的rejectedExecution(Runnable r, ThreadPoolExecutor executor); 方法蔓腐,然后默認是有4種實現方式

image

有開放的接口,那肯定是能自定義實現類的

class MyRejectedExecutionHandler implements RejectedExecutionHandler {

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("task is rejected");
    }
}

該說的方法也基本都說了龄句,用到的工作隊列(BlockingQueue)在后面會另說回论,下一篇文章就總結下jdk的線程池啦!

創(chuàng)作不易分歇,如果對你有幫助傀蓉,歡迎點贊,收藏和分享啦职抡!

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末葬燎,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子缚甩,更是在濱河造成了極大的恐慌谱净,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件擅威,死亡現場離奇詭異壕探,居然都是意外死亡,警方通過查閱死者的電腦和手機郊丛,發(fā)現死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門李请,熙熙樓的掌柜王于貴愁眉苦臉地迎上來派继,“玉大人,你說我怎么就攤上這事捻艳。” “怎么了庆猫?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵认轨,是天一觀的道長。 經常有香客問我月培,道長嘁字,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任杉畜,我火速辦了婚禮纪蜒,結果婚禮上,老公的妹妹穿的比我還像新娘此叠。我一直安慰自己纯续,他們只是感情好,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布灭袁。 她就那樣靜靜地躺著猬错,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茸歧。 梳的紋絲不亂的頭發(fā)上倦炒,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機與錄音软瞎,去河邊找鬼逢唤。 笑死,一個胖子當著我的面吹牛涤浇,可吹牛的內容都是我干的鳖藕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼只锭,長吁一口氣:“原來是場噩夢啊……” “哼吊奢!你這毒婦竟也來了?” 一聲冷哼從身側響起纹烹,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤页滚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后铺呵,有當地人在樹林里發(fā)現了一具尸體裹驰,經...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年片挂,在試婚紗的時候發(fā)現自己被綠了幻林。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贞盯。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖沪饺,靈堂內的尸體忽然破棺而出躏敢,到底是詐尸還是另有隱情,我是刑警寧澤整葡,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布件余,位于F島的核電站,受9級特大地震影響遭居,放射性物質發(fā)生泄漏啼器。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一俱萍、第九天 我趴在偏房一處隱蔽的房頂上張望端壳。 院中可真熱鬧,春花似錦枪蘑、人聲如沸损谦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽成翩。三九已至,卻和暖如春赦役,著一層夾襖步出監(jiān)牢的瞬間麻敌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工掂摔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留术羔,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓乙漓,卻偏偏與公主長得像级历,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子叭披,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內容