多線程學(xué)習(xí)使用線程池必須了解的基礎(chǔ)知識(shí)

?要使用一門技術(shù)肯定要先了解它,要使用線程池也一定要了解線程池使用的情況和基本參數(shù)永部。

使用線程池有優(yōu)勢(shì)與限制場(chǎng)景

利用Executor框架可以解耦任務(wù)的提交和任務(wù)的執(zhí)行,使得任務(wù)的提交和任務(wù)的執(zhí)行更加靈活呐矾,同時(shí)也簡(jiǎn)化了代碼苔埋,不過(guò)在有些情況下因?yàn)槿蝿?wù)不適合解耦。

比如一個(gè)任務(wù)依賴另一個(gè)任務(wù)的執(zhí)行蜒犯,或者任務(wù)只能在單線程中執(zhí)行(為了確保執(zhí)行順序)组橄,在比如對(duì)一些響應(yīng)要求比較高的任務(wù)都不適合放到線程池中執(zhí)行。

一般來(lái)說(shuō)只有任務(wù)是同類型的并且相互獨(dú)立罚随,線程池的性能才能達(dá)到最佳玉工。

線程池大小設(shè)置

線程池大小的設(shè)置也是一個(gè)需要注意的問(wèn)題,線程池設(shè)置過(guò)大會(huì)出現(xiàn)大量線程在比較少的CPU和內(nèi)存資源上發(fā)生競(jìng)爭(zhēng)淘菩,會(huì)導(dǎo)致更高的內(nèi)存使用量遵班,還有可能耗盡資源,但是如果線程池過(guò)小潮改,那么將導(dǎo)致許多空閑的處理器無(wú)法執(zhí)行工作狭郑,更多的任務(wù)處于等待狀態(tài)響應(yīng)變慢,從而降低吞吐率汇在。

線程池大小設(shè)置要考慮服務(wù)器的CPU翰萨、內(nèi)存、計(jì)算密集型還是I/O密集型等方面糕殉,尤其是計(jì)算密集型和I/O密集型屬于不同類型的任務(wù)亩鬼,他們最好分成多個(gè)線程池不要放到一個(gè)線程池中。

計(jì)算密集型運(yùn)行一般較快阿蝶,基本不會(huì)出現(xiàn)阻塞雳锋,線程可以很快處理完成馬上執(zhí)行下一個(gè)任務(wù),所以線程池大小可以設(shè)置成服務(wù)器CPU核數(shù)+1羡洁,節(jié)省資源的同時(shí)也能保證充分利用CPU玷过。

對(duì)于包含I/O或者其他阻塞操作的任務(wù),由于線程不會(huì)一直執(zhí)行,為了支持更多的任務(wù)線程池的數(shù)量設(shè)置的就會(huì)更大冶匹,當(dāng)然要更加準(zhǔn)確的設(shè)置線程池?cái)?shù)量就要估算任務(wù)的等待時(shí)間和計(jì)算時(shí)間的比值习劫。

如果任務(wù)的執(zhí)行還需要通過(guò)獲取其他線程池資源咆瘟,比如需要連接數(shù)據(jù)庫(kù)就需要數(shù)據(jù)庫(kù)線程池嚼隘,那么數(shù)據(jù)庫(kù)線程池的數(shù)量也是限制任務(wù)線程的因素之一。

線程池基本參數(shù)

線程最通用的初始化方式如下圖:

這是最基礎(chǔ)的線程池初始化方式袒餐,包含了設(shè)置線程池需要的基礎(chǔ)參數(shù)飞蛹,主要參數(shù)功能解釋如下:

corePoolSize:線程池核心線程數(shù)當(dāng)沒(méi)有任務(wù)執(zhí)行時(shí)線程池大小灸眼,當(dāng)工作隊(duì)列滿了才會(huì)創(chuàng)建超過(guò)這個(gè)數(shù)量的線程卧檐;

maximumPoolSize:最大線程數(shù),線程池能擁有的最大線程數(shù)量焰宣;

keepAliveTime:活躍時(shí)間霉囚,當(dāng)一個(gè)線程空閑超過(guò)這個(gè)時(shí)間,并且線程池線程數(shù)超過(guò)了核心線程數(shù)匕积,這個(gè)線程將被回收盈罐;

通過(guò)調(diào)節(jié)上面這三個(gè)參數(shù)可以控制資源的使用,比如newFixedThreadPool創(chuàng)建的線程池就是把corePoolSize與maximumPoolSize設(shè)置為相同值闪唆,并且永遠(yuǎn)不會(huì)超時(shí)盅粪,這樣線程池中的線程數(shù)量永遠(yuǎn)不會(huì)改變。

newCachedThreadPool是把corePoolSize設(shè)置為0悄蕾,maximumPoolSize設(shè)置為Integer的最大值票顾,keepAliveTime設(shè)置為一分鐘,線程池的數(shù)量可以根據(jù)任務(wù)數(shù)擴(kuò)展或收縮帆调,任務(wù)多就創(chuàng)建線程奠骄,沒(méi)有任務(wù)則回收所有線程。

workQueue是一個(gè)阻塞隊(duì)列番刊,用來(lái)保存等待執(zhí)行的任務(wù)戚揭,排隊(duì)基本方法有三種:無(wú)界隊(duì)列、有界隊(duì)列撵枢、同步移交民晒。

newFixedThreadPool和newSingleThreadExecutor默認(rèn)使用無(wú)界隊(duì)列LinkedBlockingQueue,如果所有工作線程都處于忙碌狀態(tài),那么任務(wù)將在隊(duì)列中等候锄禽,如果任務(wù)持續(xù)提交潜必,隊(duì)列將無(wú)限制增加。

隊(duì)列無(wú)限增加存在一定的風(fēng)險(xiǎn)沃但,比如任務(wù)提交太多太快磁滚,隊(duì)列中太多會(huì)造成內(nèi)存溢出,保證安全的辦法是使用有界隊(duì)列,比如ArrayBlockingQueue,但是使用有界隊(duì)列會(huì)出現(xiàn)新問(wèn)題垂攘,如果等待隊(duì)列滿了再繼續(xù)執(zhí)行任務(wù)該怎么處理维雇?

這里就要說(shuō)最后一個(gè)參數(shù)了“RejectedExecutionHandler handler”拒絕策略,拒絕策略主要有四種AbortPolicy(中止)晒他、CallerRunsPolicy(調(diào)用者運(yùn)行)吱型、DiscardPolicy(拋棄)、DiscardestPolicy(拋棄最舊的)陨仅;

AbortPolicy(中止):默認(rèn)拒絕策略津滞,提交任務(wù)時(shí)如果無(wú)法保存到隊(duì)列中時(shí)會(huì)拋出RejectedExecutionException。由調(diào)用捕獲并處理灼伤;

DiscardPolicy(拋棄):直接拋棄這個(gè)任務(wù)触徐;

DiscardestPolicy(拋棄最舊的):會(huì)拋棄最前面的任務(wù)也就是即將執(zhí)行的任務(wù),然后嘗試重新提交當(dāng)前任務(wù)狐赡;

CallerRunsPolicy(調(diào)用者運(yùn)行):將任務(wù)回退到調(diào)用者撞鹉;

還有一個(gè)參數(shù)“ThreadFactory threadFactory”創(chuàng)建工作線程的工廠,也就是線程池支持我們自定義創(chuàng)建線程的方式颖侄,這樣我們就可以做很多事情鸟雏,比如設(shè)置線程池創(chuàng)建線程的線程名字,還可以做一些統(tǒng)計(jì)发皿、日志等崔慧。

線程池的擴(kuò)展

ThreadPoolExecutor還提供了幾個(gè)可以重寫的方法”beforeExecute(Thread t, Runnable r)”、“afterExecute(Runnable r, Throwable t)”穴墅、“terminated()”惶室。

這幾個(gè)方法都很見(jiàn)名知意,beforeExecute拋出異常任務(wù)不會(huì)被執(zhí)行玄货,afterExecute也不執(zhí)行皇钞。任務(wù)不管是正常返回還是拋出一個(gè)異常都會(huì)執(zhí)行afterExecute方法,當(dāng)線程池完成關(guān)閉操作后會(huì)執(zhí)行terminated方法松捉,通過(guò)重寫這幾個(gè)方法可以添加日志夹界、計(jì)時(shí)、監(jiān)視隘世、統(tǒng)計(jì)等信息可柿。

總結(jié)

ThreadPoolExecutor作為多線程的基礎(chǔ),一定要了解它的基本功能丙者,學(xué)習(xí)了ThreadPoolExecutor的最基礎(chǔ)參數(shù)實(shí)際上也可以了解它的一些基本的工作流程复斥,這些最基礎(chǔ)的知識(shí)也是面試中經(jīng)常問(wèn)到的問(wèn)題。

Java程序員日常學(xué)習(xí)筆記械媒,如理解有誤歡迎各位交流討論目锭!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末评汰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子痢虹,更是在濱河造成了極大的恐慌被去,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奖唯,死亡現(xiàn)場(chǎng)離奇詭異惨缆,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)臭埋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門踪央,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)臀玄,“玉大人瓢阴,你說(shuō)我怎么就攤上這事〗∥蓿” “怎么了荣恐?”我有些...
    開(kāi)封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)累贤。 經(jīng)常有香客問(wèn)我叠穆,道長(zhǎng),這世上最難降的妖魔是什么臼膏? 我笑而不...
    開(kāi)封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任硼被,我火速辦了婚禮,結(jié)果婚禮上渗磅,老公的妹妹穿的比我還像新娘嚷硫。我一直安慰自己,他們只是感情好始鱼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布仔掸。 她就那樣靜靜地躺著,像睡著了一般医清。 火紅的嫁衣襯著肌膚如雪起暮。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天会烙,我揣著相機(jī)與錄音负懦,去河邊找鬼。 笑死柏腻,一個(gè)胖子當(dāng)著我的面吹牛纸厉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播葫盼,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼残腌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起抛猫,我...
    開(kāi)封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蟆盹,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后闺金,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逾滥,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年败匹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寨昙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡掀亩,死狀恐怖舔哪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情槽棍,我是刑警寧澤捉蚤,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站炼七,受9級(jí)特大地震影響缆巧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜豌拙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一陕悬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧按傅,春花似錦捉超、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至推捐,卻和暖如春裂问,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牛柒。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工堪簿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人皮壁。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓椭更,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蛾魄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子虑瀑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355