基于線程池的工作原理與源碼解讀
隨著cpu核數(shù)越來越多,不可避免的利用多線程技術(shù)以充分利用其計(jì)算能力。所以,多線程技術(shù)是服務(wù)端開發(fā)人員必須掌握的技術(shù)。
線程的創(chuàng)建和銷毀,都涉及到系統(tǒng)調(diào)用,比較消耗系統(tǒng)資源,所以就引入了線程池技術(shù),避免頻繁的線程創(chuàng)建和銷毀。
在Java用有一個(gè)Executors工具類,可以為我們創(chuàng)建一個(gè)線程池,其本質(zhì)就是new了一個(gè)ThreadPoolExecutor對(duì)象。線程池幾乎也是面試必考問題。本節(jié)結(jié)合源代碼,說說ThreadExecutor的工作原理
一、線程池創(chuàng)建
先看一下ThreadPoolExecutor參數(shù)最全的構(gòu)造方法:
①corePoolSize:線程池的核心線程數(shù),說白了就是,即便是線程池里沒有任何任務(wù),也會(huì)有corePoolSize個(gè)線程在候著等任務(wù)。
②maximumPoolSize:最大線程數(shù),不管你提交多少任務(wù),線程池里最多工作線程數(shù)就是maximumPoolSize。
③keepAliveTime:線程的存活時(shí)間。當(dāng)線程池里的線程數(shù)大于corePoolSize時(shí),如果等了keepAliveTime時(shí)長(zhǎng)還沒有任務(wù)可執(zhí)行,則線程退出。
⑤unit:這個(gè)用來指定keepAliveTime的單位,比如秒:TimeUnit.SECONDS。
⑥workQueue:一個(gè)阻塞隊(duì)列,提交的任務(wù)將會(huì)被放到這個(gè)隊(duì)列里。
⑦threadFactory:線程工廠,用來創(chuàng)建線程,主要是為了給線程起名字,默認(rèn)工廠的線程名字:pool-1-thread-3。
⑧handler:拒絕策略,當(dāng)線程池里線程被耗盡,且隊(duì)列也滿了的時(shí)候會(huì)調(diào)用。
以上就是創(chuàng)建線程池時(shí)用到的參數(shù),面試中經(jīng)常會(huì)有面試官問道這個(gè)問題。
二、線程池執(zhí)行流程
這里用一個(gè)圖來說明線程池的執(zhí)行流程
任務(wù)被提交到線程池,會(huì)先判斷當(dāng)前線程數(shù)量是否小于corePoolSize,如果小于則創(chuàng)建線程來執(zhí)行提交的任務(wù),否則將任務(wù)放入workQueue隊(duì)列,如果workQueue滿了,則判斷當(dāng)前線程數(shù)量是否小于maximumPoolSize,如果小于則創(chuàng)建線程執(zhí)行任務(wù),否則就會(huì)調(diào)用handler,以表示線程池拒絕接收任務(wù)。
這里以jdk1.8.0_111的源代碼為例,看一下具體實(shí)現(xiàn)。
1、先看一下線程池的executor方法
①:判斷當(dāng)前活躍線程數(shù)是否小于corePoolSize,如果小于,則調(diào)用addWorker創(chuàng)建線程執(zhí)行任務(wù)
②:如果不小于corePoolSize,則將任務(wù)添加到workQueue隊(duì)列。
③:如果放入workQueue失敗,則創(chuàng)建線程執(zhí)行任務(wù),如果這時(shí)創(chuàng)建線程失敗(當(dāng)前線程數(shù)不小于maximumPoolSize時(shí)),就會(huì)調(diào)用reject(內(nèi)部調(diào)用handler)拒絕接受任務(wù)。
2、再看下addWorker的方法實(shí)現(xiàn)
這塊代碼是在創(chuàng)建非核心線程時(shí),即core等于false。判斷當(dāng)前線程數(shù)是否大于等于maximumPoolSize,如果大于等于則返回false,即上邊說到的③中創(chuàng)建線程失敗的情況。
addWorker方法的下半部分:
①創(chuàng)建Worker對(duì)象,同時(shí)也會(huì)實(shí)例化一個(gè)Thread對(duì)象。
②啟動(dòng)啟動(dòng)這個(gè)線程
3、再到Worker里看看其實(shí)現(xiàn)
可以看到在創(chuàng)建Worker時(shí)會(huì)調(diào)用threadFactory來創(chuàng)建一個(gè)線程。上邊的②中啟動(dòng)一個(gè)線程就會(huì)觸發(fā)Worker的run方法被線程調(diào)用。
4、接下來咱們看看runWorker方法的邏輯
線程調(diào)用runWoker,會(huì)while循環(huán)調(diào)用getTask方法從workerQueue里讀取任務(wù),然后執(zhí)行任務(wù)。只要getTask方法不返回null,此線程就不會(huì)退出。
5、最后在看看getTask方法實(shí)現(xiàn)
①咱們先不管allowCoreThreadTimeOut,這個(gè)變量默認(rèn)值是false。wc>corePoolSize則是判斷當(dāng)前線程數(shù)是否大于corePoolSize。
②如果當(dāng)前線程數(shù)大于corePoolSize,則會(huì)調(diào)用workQueue的poll方法獲取任務(wù),超時(shí)時(shí)間是keepAliveTime。如果超過keepAliveTime時(shí)長(zhǎng),poll返回了null,上邊提到的while循序就會(huì)退出,線程也就執(zhí)行完了。
如果當(dāng)前線程數(shù)小于corePoolSize,則會(huì)調(diào)用workQueue的take方法阻塞在當(dāng)前。
以上這篇基于線程池的工作原理與源碼解讀就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringCloud zookeeper作為注冊(cè)中心使用介紹
ZooKeeper由雅虎研究院開發(fā),是Google Chubby的開源實(shí)現(xiàn),后來托管到Apache,于2010年11月正式成為Apache的頂級(jí)項(xiàng)目。ZooKeeper是一個(gè)經(jīng)典的分布式數(shù)據(jù)一致性解決方案,致力于為分布式應(yīng)用提供一個(gè)高性能、高可用,且具有嚴(yán)格順序訪問控制能力的分布式協(xié)調(diào)服務(wù)2022-11-11詳解Java 網(wǎng)絡(luò)IO編程總結(jié)(BIO、NIO、AIO均含完整實(shí)例代碼)
本篇文章主要介紹了Java 網(wǎng)絡(luò)IO編程總結(jié)(BIO、NIO、AIO均含完整實(shí)例代碼),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12使用Spring Data R2DBC +Postgres實(shí)現(xiàn)增刪改查功能
這篇文章主要介紹了使用Spring Data R2DBC +Postgres實(shí)現(xiàn)增刪改查功能,本文通過兩種方法給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03詳解Vue響應(yīng)式的部分實(shí)現(xiàn)
響應(yīng)式,簡(jiǎn)單來說當(dāng)數(shù)據(jù)發(fā)生變化時(shí),對(duì)數(shù)據(jù)有依賴的代碼會(huì)重新執(zhí)行。這篇文章主要為大家介紹了Vue中響應(yīng)式的部分實(shí)現(xiàn),感興趣的可以了解一下2022-12-12SpringMVC利用dropzone組件實(shí)現(xiàn)圖片上傳
這篇文章主要介紹了SpringMVC利用dropzone組件實(shí)現(xiàn)圖片上傳,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02SpringBoot Admin使用及心跳檢測(cè)原理分析
這篇文章主要介紹了SpringBoot Admin使用及心跳檢測(cè)原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11