【線程池01】-線程池的概念以及常見(jiàn)參數(shù)


title: 【線程池01】-線程池的概念以及常見(jiàn)參數(shù)
date: 2018-12-06 12:16:12
tags:

  • 多線程
  • 線程池
  • Executor
    categories: Java高并發(fā)多線程

線程池作為「Java高并發(fā)多線程」里一個(gè)重要的知識(shí)點(diǎn),在實(shí)際工作和面試過(guò)程中都有用到。
這里線程池第一篇將會(huì)整理一些線程池相關(guān)的概念看幼,以及介紹線程池的各個(gè)參數(shù)至会。

什么是線程池(what)遥椿?

線程池是一種基于池化技術(shù)管理線程的方式沾歪,類似的還有很多:數(shù)據(jù)庫(kù)連接池镀岛、Http連接池凉倚、對(duì)象池(內(nèi)存池)。提前創(chuàng)建一批資源放到池子里洞渔,在使用的時(shí)候直接來(lái)進(jìn)行資源的申請(qǐng)套媚,節(jié)約了資源創(chuàng)建和釋放的系統(tǒng)消耗,同時(shí)池子控制住大小磁椒,防止不斷的資源申請(qǐng)導(dǎo)致系統(tǒng)奔潰堤瘤。

參考美團(tuán)技術(shù)推文:「線程過(guò)多會(huì)帶來(lái)額外的開(kāi)銷,其中包括創(chuàng)建銷毀線程的開(kāi)銷浆熔、調(diào)度線程的開(kāi)銷等等本辐,同時(shí)也降低了計(jì)算機(jī)的整體性能。線程池維護(hù)多個(gè)線程,等待監(jiān)督管理者分配可并發(fā)執(zhí)行的任務(wù)慎皱。這種做法老虫,一方面避免了處理任務(wù)時(shí)創(chuàng)建銷毀線程開(kāi)銷的代價(jià),另一方面避免了線程數(shù)量膨脹導(dǎo)致的過(guò)分調(diào)度問(wèn)題茫多,保證了對(duì)內(nèi)核的充分利用祈匙。」

相比我的描述更加清晰準(zhǔn)確些天揖。

為什么要使用多線程(why)夺欲?

在傳統(tǒng)的web開(kāi)發(fā)中,服務(wù)器接收到請(qǐng)求后都需要一個(gè)線程來(lái)處理請(qǐng)求今膊。
每次請(qǐng)求過(guò)來(lái)創(chuàng)建一個(gè)線程些阅,使用起來(lái)也很方便,可是這樣就會(huì)存在這樣一個(gè)問(wèn)題:

如果并發(fā)的請(qǐng)求數(shù)量非常多斑唬,但每個(gè)線程執(zhí)行的時(shí)間很短市埋,這樣就會(huì)頻繁的創(chuàng)建和銷毀線程,如此一來(lái)會(huì)大大降低系統(tǒng)的效率恕刘⊙兀可能出現(xiàn)服務(wù)器在為每個(gè)請(qǐng)求創(chuàng)建新線程和銷毀線程上花費(fèi)的時(shí)間和消耗的系統(tǒng)資源要比處理實(shí)際的用戶請(qǐng)求的時(shí)間和資源更多。

在這種情況下雪营,線程池的存在就很有價(jià)值。線程池為線程生命周期的開(kāi)銷和資源不足問(wèn)題提供了解決方案衡便。通過(guò)對(duì)多個(gè)任務(wù)重用線程献起,線程創(chuàng)建的開(kāi)銷被分?jǐn)偟搅硕鄠€(gè)任務(wù)上。

總結(jié)來(lái)說(shuō)镣陕,線程池有如下優(yōu)點(diǎn):

  • 降低資源消耗:通過(guò)池化技術(shù)重復(fù)利用已創(chuàng)建的線程谴餐,降低線程創(chuàng)建和銷毀造成的損耗。

  • 提高響應(yīng)速度:任務(wù)到達(dá)時(shí)呆抑,無(wú)需等待線程創(chuàng)建即可立即執(zhí)行岂嗓。

  • 提高線程的可管理性:線程是稀缺資源,如果無(wú)限制創(chuàng)建鹊碍,不僅會(huì)消耗系統(tǒng)資源厌殉,還會(huì)因?yàn)榫€程的不合理分布導(dǎo)致資源調(diào)度失衡,降低系統(tǒng)的穩(wěn)定性侈咕。使用線程池可以進(jìn)行統(tǒng)一的分配公罕、調(diào)優(yōu)和監(jiān)控。

  • 提供更多更強(qiáng)大的功能:線程池具備可拓展性耀销,允許開(kāi)發(fā)人員向其中增加更多的功能楼眷。比如延時(shí)定時(shí)線程池ScheduledThreadPoolExecutor,就允許任務(wù)延期執(zhí)行或定期執(zhí)行。

如何使用線程池(how)罐柳?

Java中主要是使用J.U.C提供的ThreadPoolExecutor類來(lái)使用線程池掌腰,這里主要先總結(jié)整理下線程池的幾個(gè)常用方法以及線程池的常用參數(shù),后面再針對(duì)具體內(nèi)部的代碼和使用做整理张吉。

創(chuàng)建線程池都可以通過(guò)Executors類來(lái)實(shí)現(xiàn)齿梁,此類主要提供了一系列工廠方法來(lái)創(chuàng)建線程池,返回的線程池都實(shí)現(xiàn)了ExrcutorService接口芦拿。

//創(chuàng)建一個(gè)固定大小的線程池士飒,超出的部分在隊(duì)列等待
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)

//創(chuàng)建一個(gè)單線程的線程池
public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)

//創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過(guò)處理需要蔗崎,可靈活回收空閑線程(60s)酵幕,若無(wú)可回收,則新建線程缓苛。
public static ExecutorService newCachedThreadPool()
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)

//創(chuàng)建一個(gè)單線程線程池芳撒,支持定時(shí)及周期性任務(wù)執(zhí)行
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)

//創(chuàng)建一個(gè)定長(zhǎng)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)

//會(huì)創(chuàng)建一個(gè)含有足夠多線程的線程池未桥,來(lái)維持相應(yīng)的并行級(jí)別
//它會(huì)通過(guò)工作竊取的方式笔刹,使得多核的 CPU 不會(huì)閑置,總會(huì)有活著的線程讓 CPU 去運(yùn)行
public static ExecutorService newWorkStealingPool(int parallelism)
public static ExecutorService newWorkStealingPool()

但是冬耿,阿里開(kāi)發(fā)手冊(cè)有如下一條規(guī)定:

【強(qiáng)制】線程池不允許使用 Executors 去創(chuàng)建舌菜,而是通過(guò) ThreadPoolExecutor 的方式

這是因?yàn)?Executor.newCachedThreadPool() 和 Executors#newScheduledThreadPool() 兩個(gè)方法最大線程數(shù)為Integer.MAX_VALUE,如果達(dá)到最大值亦镶,系統(tǒng)可能OOM日月。Executors.newSingleThreadExecutor() 和Executors.newFixedThreadPool() 兩個(gè)方法的 workQueue 參數(shù)為new LinkedBlockingQueue<Runnable>(),容量為Integer.MAX_VALUE缤骨,如果隊(duì)列非常大爱咬,也會(huì)有OOM風(fēng)險(xiǎn)。

所以一般情況下使用線程池使用ThreadPoolExecutor 提供的構(gòu)造進(jìn)行線程池創(chuàng)建绊起,實(shí)際上Executors 提供的方法就是對(duì)此構(gòu)造的封裝精拟。最底層的構(gòu)造方法如下,下面將會(huì)依次介紹各個(gè)參數(shù)虱歪。

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,TimeUnit unit,
                              BlockingQueue<Runnable> workQueue, 
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

核心參數(shù)說(shuō)明

  • corePoolSize
    核心線程數(shù)蜂绎,核心線程會(huì)一直存活,即使沒(méi)有任務(wù)需要處理实蔽。當(dāng)線程數(shù)小于核心線程數(shù)時(shí)荡碾,即使現(xiàn)有的線程空閑,線程池也會(huì)優(yōu)先創(chuàng)建新線程來(lái)處理任務(wù)局装,而不是直接交給現(xiàn)有的線程處理坛吁。核心線程在allowCoreThreadTimeout被設(shè)置為true時(shí)會(huì)超時(shí)退出劳殖,默認(rèn)情況下不會(huì)退出。
  • maxPoolSize
    最大線程數(shù)量拨脉,當(dāng)線程數(shù)大于或等于核心線程哆姻,且任務(wù)隊(duì)列已滿時(shí),線程池會(huì)創(chuàng)建新的線程玫膀,直到線程數(shù)量達(dá)到maxPoolSize矛缨。如果線程數(shù)已等于maxPoolSize,且任務(wù)隊(duì)列已滿帖旨,則已超出線程池的處理能力箕昭,線程池會(huì)拒絕處理任務(wù)而拋出異常。 |
  • keepAliveTime
    線程最大存活時(shí)間解阅,超過(guò)核心線程數(shù)的線程落竹,如果在此參數(shù)指定的時(shí)間內(nèi)還沒(méi)有接收到新任務(wù),則會(huì)被銷毀货抄。也就是說(shuō)此參數(shù)是指定超過(guò)核心線程數(shù)的空閑線程的最大存活時(shí)間 |
  • workQueue
    等待任務(wù)隊(duì)列 述召,用來(lái)保存通過(guò)execute(Runnable command)方法提交的未執(zhí)行的任務(wù)。也就是在任務(wù)執(zhí)行之前用來(lái)保存任務(wù)的隊(duì)列蟹地。 |
  • threadFactory
    線程工廠积暖,生成線程的工廠類
  • handler
    線程池的飽和策略,如果阻塞隊(duì)列滿了并且沒(méi)有空閑的線程怪与,這時(shí)如果繼續(xù)提交任務(wù)夺刑,就需要采取一種策略處理該任務(wù)

線程池提供了四種策略:

  • AbortPolicy : 直接拋出RejectedExecutionException異常 這是默認(rèn)策略;
  • CallerRunsPolicy:用調(diào)用者所在的線程來(lái)執(zhí)行任務(wù)分别;
  • DiscardOldestPolicy:丟棄阻塞隊(duì)列中靠最前的任務(wù)性誉,并執(zhí)行當(dāng)前任務(wù);
  • DiscardPolicy:直接丟棄任務(wù)茎杂;

具體的線程池使用示例會(huì)在下一篇中總結(jié)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纫雁,一起剝皮案震驚了整個(gè)濱河市煌往,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌轧邪,老刑警劉巖刽脖,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異忌愚,居然都是意外死亡曲管,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)硕糊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)院水,“玉大人腊徙,你說(shuō)我怎么就攤上這事∶誓常” “怎么了撬腾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)恢恼。 經(jīng)常有香客問(wèn)我民傻,道長(zhǎng),這世上最難降的妖魔是什么场斑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任漓踢,我火速辦了婚禮,結(jié)果婚禮上漏隐,老公的妹妹穿的比我還像新娘喧半。我一直安慰自己,他們只是感情好锁保,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布薯酝。 她就那樣靜靜地躺著,像睡著了一般爽柒。 火紅的嫁衣襯著肌膚如雪吴菠。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天浩村,我揣著相機(jī)與錄音做葵,去河邊找鬼。 笑死心墅,一個(gè)胖子當(dāng)著我的面吹牛酿矢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播怎燥,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瘫筐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了铐姚?” 一聲冷哼從身側(cè)響起策肝,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎隐绵,沒(méi)想到半個(gè)月后之众,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡依许,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年棺禾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峭跳。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膘婶,死狀恐怖缺前,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情竣付,我是刑警寧澤诡延,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站古胆,受9級(jí)特大地震影響肆良,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逸绎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一惹恃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧棺牧,春花似錦巫糙、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至乏悄,卻和暖如春浙值,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背檩小。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工开呐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人规求。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓筐付,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親阻肿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓦戚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

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