Java 多線程(九)- 理解線程池

線程池

合理利用線程池能夠帶來以下好處:

  • 降低消耗。通過重復利用已創(chuàng)建的線程降低創(chuàng)建和銷毀線程的消耗;
  • 提高響應速度。當任務到達時霹购,任務可以不需要等待線程創(chuàng)建就能立即執(zhí)行;
  • 提高穩(wěn)定性句葵。如果無限制的創(chuàng)建線程厕鹃,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性乍丈,使用線程池可以進行統(tǒng)一的分配剂碴,調(diào)優(yōu)和監(jiān)控。

為了使線程池的性能達到最優(yōu)轻专,需要注意:

  • 任務時同類型的忆矛,并且相互獨立;因為當在線程池中執(zhí)行獨立的任務時,可以隨意的改變線程池的大小和配置催训,這些修改只會對執(zhí)行性能產(chǎn)生影響洽议。而且如果提交的任務依賴其他任務,很可能產(chǎn)生死鎖漫拭。
  • 盡量避免執(zhí)行時間較長的任務亚兄。如果執(zhí)行時間很長的任務比較多,除非線程池很大采驻,否則將可能造成“阻塞”审胚,線程池的響應性會變的很糟糕。

ThreadPoolExecutor 框架

在 JUC 中礼旅,ThreadPoolExecutor 實現(xiàn)了一個可配置高性能的線程池膳叨。庫里已經(jīng)封裝了一些常用的的線程池,如果現(xiàn)有的不能滿足實際需求痘系,也可以繼承它進行修改菲嘴。ThreadPoolExecutor 繼承關系如下圖所示:

類圖

其中最核心的是 submit 接口,sumbit 內(nèi)部調(diào)用 execute汰翠,無非做了一次封裝龄坪,生成了 Future 對象,通過該對象可以獲取任務結(jié)果复唤。

構(gòu)造函數(shù)
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler);
  • int corePoolSize

線程池的基本大邢つ:當提交一個任務到線程池時,線程池會創(chuàng)建一個線程來執(zhí)行任務苟穆,即使其他空閑的基本線程能夠執(zhí)行新任務也會創(chuàng)建線程,等到需要執(zhí)行的任務數(shù)大于線程池基本大小時就不再創(chuàng)建唱星。如果調(diào)用了線程池的prestartAllCoreThreads方法雳旅,線程池會提前創(chuàng)建并啟動所有基本線程。

  • int maximumPoolSize

線程池最大大小间聊,線程池允許創(chuàng)建的最大線程數(shù)攒盈。如果隊列已滿,并且已創(chuàng)建的線程數(shù)小于最大線程數(shù)哎榴,則線程池會再創(chuàng)建新的線程執(zhí)行任務型豁。值得注意的是如果使用了無界的任務隊列這個參數(shù)就沒什么效果

  • long keepAliveTime

線程活動保持時間:線程池的工作線程空閑后,保持存活的時間尚蝌。所以如果任務很多迎变,并且每個任務執(zhí)行的時間比較短,可以調(diào)大這個時間飘言,提高線程的利用率衣形。

  • TimeUnit unit

線程活動保持時間的單位

  • BlockingQueue<Runnable> workQueue

用于保存等待執(zhí)行的任務的阻塞隊列。一般選用 LinkedBlockingQueue 和 SynchronousQueue姿鸿。

  • ThreadFactory threadFactory

用于設置創(chuàng)建線程的工廠谆吴,可以通過線程工廠給每個創(chuàng)建出來的線程設置更有意義的名字倒源,Debug和定位問題時非常又幫助。

  • RejectedExecutionHandler handler

當隊列和線程池都滿了句狼,說明線程池處于飽和狀態(tài)笋熬,那么必須采取一種策略處理提交的新任務。這個策略默認情況下是AbortPolicy腻菇,表示無法處理新任務時拋出異常胳螟。以下是 JDK 提供的四種策略

  1. AbortPolicy:直接拋出異常。
  2. CallerRunsPolicy:只用調(diào)用者所在線程來運行任務芜繁。
  3. DiscardOldestPolicy:丟棄隊列里最近的一個任務旺隙,并執(zhí)行當前任務。
  4. DiscardPolicy:不處理骏令,丟棄掉蔬捷。
參數(shù)與管理機制

ThreadPoolExecutor 根據(jù) corePoolSize, maximumPoolSize榔袋,keepAliveTime 等參數(shù)管理線程周拐。如果線程數(shù)量小于 corePoolSize,則新任務到來都會生成新的線程凰兑。如果數(shù)量大于 corePoolSize妥粟,新任務會被加入到阻塞隊列中去。如果阻塞隊列有界且滿吏够,同時線程數(shù)量還小于 maximumPoolSize勾给,則會生成新的工作線程幫助完成任務。如果很不幸線程數(shù)超過 maximumPoolSize锅知,則按照 RejectedExecutionHandler 處理新到的任務播急。

如果任務完成且線程處于等待狀態(tài),ThreadPoolExecutor 會根據(jù) keepAliveTime 銷毀空閑線程售睹,直到線程數(shù)量不大于 corePoolSize桩警。但是若調(diào)用過 allowCoreThreadTimeOut 接口,corePoolSize 下的線程也會被銷毀昌妹。

線程管理機制如下圖所示:


線程管理機制

常用線程池

newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

corePoolSize 和 maximumPoolSize 同為 nThreads捶枢, 使用無界阻塞隊列 LinkedBlockingQueue。因此線程池中線程數(shù)量固定飞崖,多余的任務會被加入無界鏈表阻塞隊列烂叔。

newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

corePoolSize 和 maximumPoolSize 同為 1, 使用無界阻塞隊列 LinkedBlockingQueue蚜厉。因此線程池中只有 1 條線程长已,多余的任務會被加入無界鏈表阻塞隊列。

newCachedThreadPool
 public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

corePoolSize 為 0, maximumPoolSize 是 Integer 極大值术瓮,采用 SynchronousQueue 阻塞隊列康聂。也就是說若沒有空閑線程,線程池會為每個任務創(chuàng)建一個線程胞四√裰空閑線程會等待 60 秒接收新任務,若沒有新任務則會被銷毀辜伟。最后所有線程都會被銷毀氓侧。

合理配置

如何合理配置線程池大小,僅供參考导狡。一般需要根據(jù)任務的類型來配置線程池大性枷铩:

  • 如果是CPU密集型任務,就需要盡量壓榨CPU旱捧,參考值可以設為 NCPU+1

  • 如果是IO密集型任務独郎,參考值可以設置為2*NCPU,因為并不是所有任務都是在計算中枚赡,很多是等候 IO氓癌。

當然,這只是一個參考值贫橙,具體的設置還需要根據(jù)實際情況進行調(diào)整贪婉,比如可以先將線程池大小設置為參考值,再觀察任務運行情況和系統(tǒng)負載卢肃、資源利用率來進行適當調(diào)整疲迂。

內(nèi)容來源

Java 并發(fā)編程實戰(zhàn)

http://825635381.iteye.com/blog/2184680

http://www.cnblogs.com/zhanjindong/p/java-concurrent-package-ThreadPoolExecutor.html

http://ifeve.com/java-threadpool/

http://blog.csdn.net/zxc123e/article/details/51891200

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市莫湘,隨后出現(xiàn)的幾起案子鬼譬,更是在濱河造成了極大的恐慌,老刑警劉巖逊脯,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異竣贪,居然都是意外死亡军洼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門演怎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匕争,“玉大人,你說我怎么就攤上這事爷耀「噬#” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長跑杭。 經(jīng)常有香客問我铆帽,道長,這世上最難降的妖魔是什么德谅? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任爹橱,我火速辦了婚禮,結(jié)果婚禮上窄做,老公的妹妹穿的比我還像新娘愧驱。我一直安慰自己,他們只是感情好椭盏,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布组砚。 她就那樣靜靜地躺著,像睡著了一般掏颊。 火紅的嫁衣襯著肌膚如雪糟红。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天蚯舱,我揣著相機與錄音改化,去河邊找鬼。 笑死枉昏,一個胖子當著我的面吹牛陈肛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兄裂,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼句旱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了晰奖?” 一聲冷哼從身側(cè)響起谈撒,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匾南,沒想到半個月后啃匿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蛆楞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年溯乒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片豹爹。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡裆悄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出臂聋,到底是詐尸還是另有隱情光稼,我是刑警寧澤或南,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站艾君,受9級特大地震影響采够,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腻贰,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一吁恍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧播演,春花似錦冀瓦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至洲炊,卻和暖如春感局,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暂衡。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工询微, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狂巢。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓撑毛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親唧领。 傳聞我的和親對象是個殘疾皇子藻雌,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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