Java線程池解析

Java的一大優(yōu)勢是能完成多線程任務(wù)缎浇,對(duì)線程的封裝和調(diào)度非常好,那么它又是如何實(shí)現(xiàn)的呢蒋院?

jdk的包下和線程相關(guān)類的類圖买决。

線程相關(guān)類圖

從上圖可以看出Java線程池的實(shí)現(xiàn)類主要有兩個(gè)類ForkJoinPool和ThreadPoolExecutor。

ThreadPoolExecutor :標(biāo)準(zhǔn)線程池

ScheduledThreadPoolExecutor: 支持延遲任務(wù)的線程池

ForkJoinPool :類似于ThreadPoolExecutor 带猴,但是使用work-stealing模式昔汉,其會(huì)為線程池中每個(gè)線程創(chuàng)建一個(gè)隊(duì)列,從而用work-stealing(任務(wù)竊人┣濉)算法使得線程可以從其他線程隊(duì)列里竊取任務(wù)來執(zhí)行靶病。即如果自己的任務(wù)處理完成了,則可以去忙碌的工作線程那里竊取任務(wù)來執(zhí)行

使用Executors來創(chuàng)建線程池口予。

1娄周、創(chuàng)建單線程的線程池。

public static ExecutorServicenewSingleThreadExecutor(){

? ? return new FinalizableDelegatedExecutorService

(new ThreadPoolExecutor(1, 1,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0L, TimeUnit.MILLISECONDS,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new LinkedBlockingQueue<Runnable>()));

}

2苹威、創(chuàng)建固定數(shù)量的線程池

public static ExecutorServicenewFixedThreadPool(int nThreads) {

? ? return new ThreadPoolExecutor(nThreads, nThreads,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0L, TimeUnit.MILLISECONDS,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new LinkedBlockingQueue<Runnable>());

}

3昆咽、創(chuàng)建可緩沖的線程池

public static ExecutorServicenewCachedThreadPool(){

? ? return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 60L, TimeUnit.SECONDS,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new SynchronousQueue<Runnable>());

}

其中ThreadPoolExecutor的構(gòu)造函數(shù)中有幾個(gè)參數(shù)驾凶,現(xiàn)在介紹這些參數(shù)牙甫,是理解線程池工作原理的重要方式:

1、第一個(gè)參數(shù):int corePoolSIze调违,核心池大小窟哺,也就是線程池中會(huì)維持不被釋放的線程數(shù)量。我們可以看到FixedThreadPool中這個(gè)參數(shù)值就是設(shè)定的線程數(shù)量技肩,而SingleThreadExcutor中就是1且轨,newCachedThreadPool中就是0,不會(huì)維持虚婿,只會(huì)緩存60L旋奢。但需要注意的是,在線程池剛創(chuàng)建時(shí)然痊,里面并沒有建好的線程至朗,只有當(dāng)有任務(wù)來的時(shí)候才會(huì)創(chuàng)建(除非調(diào)用方法prestartAllCoreThreads()與prestartCoreThread()方法),在corePoolSize數(shù)量范圍的線程在完成任務(wù)后不會(huì)被回收剧浸。

2锹引、第二個(gè)參數(shù):int maximumPoolSize矗钟,線程池的最大線程數(shù),代表著線程池中能創(chuàng)建多少線程池嫌变。超出corePoolSize吨艇,小于maximumPoolSize的線程會(huì)在執(zhí)行任務(wù)結(jié)束后被釋放。此配置在CatchedThreadPool中有效腾啥。

3东涡、第三個(gè)參數(shù):long keepAliveTime,剛剛說到的會(huì)被釋放的線程緩存的時(shí)間倘待。我們可以看到软啼,正如我們所說的,在CachedThreadPool()構(gòu)造過程中延柠,會(huì)被設(shè)置緩存時(shí)間為60s(時(shí)間單位由第四個(gè)參數(shù)控制)祸挪。

4、第四個(gè)參數(shù):TimeUnit unit贞间,設(shè)置第三個(gè)參數(shù)keepAliveTime的時(shí)間單位贿条。

5、第五個(gè)參數(shù):存儲(chǔ)等待執(zhí)行任務(wù)的阻塞隊(duì)列增热,有多種選擇整以,分別介紹:

SynchronousQueue——直接提交策略,適用于CachedThreadPool峻仇。它將任務(wù)直接提交給線程而不保持它們公黑。如果不存在可用于立即運(yùn)行任務(wù)的線程,則試圖把任務(wù)加入隊(duì)列將失敗摄咆,因此會(huì)構(gòu)造一個(gè)新的線程凡蚜。此策略可以避免在處理可能具有內(nèi)部依賴性的請(qǐng)求集時(shí)出現(xiàn)鎖。直接提交通常要求最大的 maximumPoolSize 以避免拒絕新提交的任務(wù)(正如CachedThreadPool這個(gè)參數(shù)的值為Integer.MAX_VALUE)吭从。當(dāng)任務(wù)以超過隊(duì)列所能處理的量朝蜘、連續(xù)到達(dá)時(shí),此策略允許線程具有增長的可能性涩金。吞吐量較高谱醇。

LinkedBlockingQueue——無界隊(duì)列,適用于FixedThreadPool與SingleThreadExcutor步做「笨剩基于鏈表的阻塞隊(duì)列,創(chuàng)建的線程數(shù)不會(huì)超過corePoolSizes(maximumPoolSize值與其一致)全度,當(dāng)線程正忙時(shí)煮剧,任務(wù)進(jìn)入隊(duì)列等待。按照FIFO原則對(duì)元素進(jìn)行排序,吞吐量高于ArrayBlockingQueue轿秧。

ArrayBlockingQueue——有界隊(duì)列中跌,有助于防止資源耗盡,但是可能較難調(diào)整和控制菇篡。隊(duì)列大小和最大池大小可能需要相互折衷:使用大型隊(duì)列和小型池可以最大限度地降低 CPU 使用率漩符、操作系統(tǒng)資源和上下文切換開銷,但是可能導(dǎo)致人工降低吞吐量驱还。如果任務(wù)頻繁阻塞(例如嗜暴,如果它們是 I/O邊界),則系統(tǒng)可能為超過您許可的更多線程安排時(shí)間议蟆。使用小型隊(duì)列通常要求較大的池大小闷沥,CPU使用率較高,但是可能遇到不可接受的調(diào)度開銷咐容,這樣也會(huì)降低吞吐量舆逃。

ThreadPoolExcutor的構(gòu)造方式不僅有這一種,總共有四種戳粒,還可以在最后加入一個(gè)參數(shù)以控制線程池任務(wù)超額處理策略:

當(dāng)用來緩存待處理任務(wù)的隊(duì)列已滿時(shí)路狮,又加入了新的任務(wù),那么這時(shí)候就該考慮如何處理這個(gè)任務(wù)蔚约。

可以通過實(shí)現(xiàn)RejectedExceptionHandler接口奄妨,實(shí)現(xiàn)rejectedException(ThreadPoolExecutor e, Runnable r)方法自定義操作。但通常我們使用JDK提供了4種處理策略苹祟,在ThreadPoolExecutor構(gòu)造時(shí)以參數(shù)傳入:

ThreadPoolExcutor.AbortPolicy()——直接拋出異常砸抛,默認(rèn)操作

ThreadPoolExcutor.CallerRunsPolicy()——只用調(diào)用者所在線程來運(yùn)行任務(wù)

ThreadPoolExcutor.DiscardOldersPolicy()——丟棄隊(duì)列里最近的一個(gè)任務(wù),并執(zhí)行當(dāng)前任務(wù)

ThreadPoolExcutor.DiscardPolicy()——不處理树枫,直接丟掉


接著直焙,我們看一下線程池中比較重要的execute方法,該方法用于向線程池中添加一個(gè)任務(wù)团赏。

execute方法

核心模塊用紅框標(biāo)記了箕般。

第一個(gè)紅框:workerCountOf方法根據(jù)ctl的低29位耐薯,得到線程池的當(dāng)前線程數(shù)舔清,如果線程數(shù)小于corePoolSize,則執(zhí)行addWorker方法創(chuàng)建新的線程執(zhí)行任務(wù)曲初;

第二個(gè)紅框:判斷線程池是否在運(yùn)行体谒,如果在,任務(wù)隊(duì)列是否允許插入臼婆,插入成功再次驗(yàn)證線程池是否運(yùn)行抒痒,如果不在運(yùn)行,移除插入的任務(wù)颁褂,然后拋出拒絕策略故响。如果在運(yùn)行傀广,沒有線程了,就啟用一個(gè)線程彩届。

第三個(gè)紅框:如果添加非核心線程失敗伪冰,就直接拒絕了。


接下來樟蠕,我們看看如何添加一個(gè)工作線程的贮聂?

添加worker線程

從方法execute的實(shí)現(xiàn)可以看出:addWorker主要負(fù)責(zé)創(chuàng)建新的線程并執(zhí)行任務(wù),代碼如下(這里代碼有點(diǎn)長寨辩,沒關(guān)系吓懈,也是分塊的,總共有5個(gè)關(guān)鍵的代碼塊):

第一個(gè)紅框:做是否能夠添加工作線程條件過濾:

判斷線程池的狀態(tài)靡狞,如果線程池的狀態(tài)值大于或等SHUTDOWN耻警,則不處理提交的任務(wù),直接返回甸怕;

第二個(gè)紅框:做自旋钾虐,更新創(chuàng)建線程數(shù)量:

通過參數(shù)core判斷當(dāng)前需要?jiǎng)?chuàng)建的線程是否為核心線程,如果core為true夯尽,且當(dāng)前線程數(shù)小于corePoolSize袱箱,則跳出循環(huán),開始創(chuàng)建新的線程

有人或許會(huì)疑問 retry 是什么式曲?這個(gè)是java中的goto語法妨托。只能運(yùn)用在break和continue后面。

接著看后面的代碼:

第一個(gè)紅框:獲取線程池主鎖吝羞。

線程池的工作線程通過Woker類實(shí)現(xiàn)兰伤,通過ReentrantLock鎖保證線程安全。

第二個(gè)紅框:添加線程到workers中(線程池中)钧排。

第三個(gè)紅框:啟動(dòng)新建的線程敦腔。

接下來,我們看看workers是什么恨溜。

一個(gè)hashSet符衔。所以,線程池底層的存儲(chǔ)結(jié)構(gòu)其實(shí)就是一個(gè)HashSet糟袁。

worker線程處理隊(duì)列任務(wù)

第一個(gè)紅框:是否是第一次執(zhí)行任務(wù)判族,或者從隊(duì)列中可以獲取到任務(wù)。

第二個(gè)紅框:獲取到任務(wù)后项戴,執(zhí)行任務(wù)開始前操作鉤子形帮。

第三個(gè)紅框:執(zhí)行任務(wù)。

第四個(gè)紅框:執(zhí)行任務(wù)后鉤子。

這兩個(gè)鉤子(beforeExecute辩撑,afterExecute)允許我們自己繼承線程池界斜,做任務(wù)執(zhí)行前后處理。

到這里暫時(shí)結(jié)束

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末合冀,一起剝皮案震驚了整個(gè)濱河市锄蹂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌水慨,老刑警劉巖得糜,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異晰洒,居然都是意外死亡朝抖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門谍珊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來治宣,“玉大人,你說我怎么就攤上這事砌滞∥暄” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵贝润,是天一觀的道長绊茧。 經(jīng)常有香客問我,道長打掘,這世上最難降的妖魔是什么华畏? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮尊蚁,結(jié)果婚禮上亡笑,老公的妹妹穿的比我還像新娘。我一直安慰自己横朋,他們只是感情好仑乌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著琴锭,像睡著了一般晰甚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上祠够,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天压汪,我揣著相機(jī)與錄音,去河邊找鬼古瓤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的落君。 我是一名探鬼主播穿香,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼绎速!你這毒婦竟也來了皮获?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤纹冤,失蹤者是張志新(化名)和其女友劉穎洒宝,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萌京,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡雁歌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了知残。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片靠瞎。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖求妹,靈堂內(nèi)的尸體忽然破棺而出乏盐,到底是詐尸還是另有隱情,我是刑警寧澤制恍,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布父能,位于F島的核電站,受9級(jí)特大地震影響净神,放射性物質(zhì)發(fā)生泄漏法竞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一强挫、第九天 我趴在偏房一處隱蔽的房頂上張望岔霸。 院中可真熱鬧,春花似錦俯渤、人聲如沸呆细。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽絮爷。三九已至,卻和暖如春梨树,著一層夾襖步出監(jiān)牢的瞬間坑夯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國打工抡四, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留柜蜈,地道東北人仗谆。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像淑履,于是被迫代替她去往敵國和親隶垮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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

  • 為什么使用線程池 當(dāng)我們?cè)谑褂镁€程時(shí)秘噪,如果每次需要一個(gè)線程時(shí)都去創(chuàng)建一個(gè)線程狸吞,這樣實(shí)現(xiàn)起來很簡單,但是會(huì)有一個(gè)問題...
    閩越布衣閱讀 4,292評(píng)論 10 45
  • Java的一大優(yōu)勢是能完成多線程任務(wù)指煎,對(duì)線程的封裝和調(diào)度非常好蹋偏,那么它又是如何實(shí)現(xiàn)的呢? jdk的包下和線程相關(guān)類...
    whthomas閱讀 1,012評(píng)論 0 9
  • 本文是我自己在秋招復(fù)習(xí)時(shí)的讀書筆記至壤,整理的知識(shí)點(diǎn)威始,也是為了防止忘記,尊重勞動(dòng)成果崇渗,轉(zhuǎn)載注明出處哦字逗!如果你也喜歡,那...
    波波波先森閱讀 11,263評(píng)論 4 56
  • 我認(rèn)識(shí)小蔣的時(shí)候宅广,他才18歲葫掉。我站在百花洲麥當(dāng)勞門前的路邊,揚(yáng)手一招跟狱,一輛藍(lán)色的士便图蠛瘢靠前來,小蔣憨厚的笑臉探了出...
    夢(mèng)1212閱讀 374評(píng)論 0 0
  • 復(fù)盤內(nèi)容:精度The Kindness of Sttangers 1驶臊,從本篇文章/音頻/視頻中我學(xué)到的最重要的概念...
    陽噠噠閱讀 168評(píng)論 3 1