boy-learning-thread | 1.1.6 線程池原理

相關(guān)源碼:boy-learning-thread
個(gè)人博客:http://bruce.bugmakers.club
內(nèi)容來自《網(wǎng)易微專業(yè) - 高性能編程章節(jié)》

線程池原理

1、為什么要用線程池

線程是不是越多越好?

1右遭、線程在 java 中是一個(gè)對(duì)象郊供,更是操作系統(tǒng)中的資源驴娃,線程創(chuàng)建妓忍、銷毀需要時(shí)間。如果 “創(chuàng)建時(shí)間 + 銷毀時(shí)間 > 執(zhí)行任務(wù)時(shí)間” 就恨不合算峭沦。

2、java 對(duì)象占用堆內(nèi)存征炼,操作系統(tǒng)線程占用系統(tǒng)內(nèi)存析既,根據(jù) jvm 規(guī)范,一個(gè)線程默認(rèn)最大棧大小 1M谆奥,這個(gè)空間是需要從系統(tǒng)內(nèi)存中分配的眼坏。線程過多,會(huì)消耗很多內(nèi)存酸些。

3宰译、操作系統(tǒng)需要頻繁切換線程上下文(大家都想被執(zhí)行),線程過多會(huì)影響性能魄懂。

線程池的推出沿侈,就是為了方便的控制線程數(shù)量。

2市栗、線程池原理 - 概念

1缀拭、線程池管理器:用于創(chuàng)建并管理線程池,包括:創(chuàng)建線程池填帽、銷毀線程池蛛淋、添加新任務(wù);

2篡腌、工作線程:線程池中的線程铣鹏,在沒有任務(wù)時(shí)處于等待狀態(tài),可以循環(huán)的執(zhí)行任務(wù)哀蘑;

3、任務(wù)接口:每個(gè)任務(wù)必須實(shí)現(xiàn)的接口葵第,以供工作線程調(diào)度任務(wù)的執(zhí)行绘迁,它主要規(guī)定了:任務(wù)的入口、任務(wù)執(zhí)行完后的收尾工作卒密、任務(wù)的狀態(tài)缀台;

4、任務(wù)隊(duì)列:用于存放沒有處理的任務(wù)哮奇。以供一種緩沖機(jī)制膛腐。

2.1、線程池 API - 接口定義和實(shí)現(xiàn)類

類型 名稱 描述
接口 Executor 最上層接口鼎俘,定義了執(zhí)行任務(wù)的方法 execute
接口 ExecutorService 繼承了 Executor 接口哲身,拓展了 Callable、Future贸伐、關(guān)閉方法
接口 ScheduledExecutorService 繼承了 ExecutorService勘天,增加了定時(shí)任務(wù)相關(guān)的方法
實(shí)現(xiàn)類 ThreadPoolExecutor 基礎(chǔ)、標(biāo)準(zhǔn)的線程池實(shí)現(xiàn)類
實(shí)現(xiàn)類 ScheduledThreadPoolExecutor 繼承了 ThreadPoolExecutor,實(shí)現(xiàn)了 ScheduledExecutorService 中相關(guān)定時(shí)任務(wù)的方法

可以認(rèn)為 ScheduledThreadPoolExecutor 是最豐富的實(shí)現(xiàn)類脯丝。

2.2商膊、線程池 API - 方法定義

ExecutorService

// 監(jiān)測(cè) ExecutorService 是否已關(guān)閉,直到所有任務(wù)完成執(zhí)行宠进,或超時(shí)發(fā)生晕拆,或當(dāng)前線程被中斷  
awaitTermination(long timeout, TimeUnit unit);

// 執(zhí)行給定的任務(wù)集合,執(zhí)行完畢后材蹬,返回結(jié)果
invokeAll(Collection<? extends Callable<T>> tasks);

// 執(zhí)行給定的任務(wù)集合实幕,執(zhí)行完畢或者超時(shí)后,返回結(jié)果赚导,其他任務(wù)終止
invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit);

// 執(zhí)行給定的任務(wù)集合茬缩,任意一個(gè)任務(wù)執(zhí)行成功后,返回結(jié)果吼旧,其他任務(wù)終止
invokeAny(Collection<? extends Callable<T>> tasks);

// 執(zhí)行給定的任務(wù)集合凰锡,任意一個(gè)任務(wù)執(zhí)行成功或超時(shí)后,返回結(jié)果圈暗,其他任務(wù)終止
invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit);

// 如果線程池關(guān)閉掂为,則返回treu
isShutdown();

// 如果關(guān)閉后,所有任務(wù)都已經(jīng)執(zhí)行完畢员串,則返回true
isTerminated();

// 優(yōu)雅關(guān)閉線程池勇哗,之前已經(jīng)提交的任務(wù)將被執(zhí)行,但不接受新的任務(wù)
shutdown();

// 嘗試停止所有正在執(zhí)行的任務(wù)寸齐,停止等待任務(wù)的處理欲诺,并返回等待執(zhí)行任務(wù)的列表
shutdownNow();

// 提交一個(gè)用于執(zhí)行的 Callable 返回任務(wù),并返回一個(gè) Future 對(duì)象渺鹦,用于獲取 Callable 執(zhí)行結(jié)果
submit(Callable<T> task);

// 提交可運(yùn)行任務(wù)以執(zhí)行扰法,并返回一個(gè) Future 對(duì)象,執(zhí)行結(jié)果為 null
submit(Runnable task);

// 提交可運(yùn)行任務(wù)以執(zhí)行塞颁,并返回一個(gè) Future 對(duì)象祠锣,執(zhí)行結(jié)果為傳入的 result
sumit(Runnable task, T result);

ScheduledExecutorService

// 創(chuàng)建并執(zhí)行一個(gè)一次性任務(wù)妆棒,過了延遲時(shí)間就會(huì)被執(zhí)行
schedule(Callable<T> callable, long delay, TimeUnit unit);
schedule(Runnable command, long delay, TimeUnit unit);

// 創(chuàng)建并執(zhí)行一個(gè)周期性任務(wù)馋评,過了延遲時(shí)間會(huì)第一次執(zhí)行,執(zhí)行過程發(fā)生異常蜕青,那么任務(wù)就停止了
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
scheduleWithFixedDelay(Runnable command, long initialDelay, long period, TimeUnit unit);

scheduleAtFixedRate 方法渺绒,一次任務(wù)執(zhí)行時(shí)長(zhǎng)超過周期時(shí)間,下次任務(wù)在該次任務(wù)執(zhí)行完之后,立即執(zhí)行。
schedualWithFixedDelay 方法,一次任務(wù)執(zhí)行時(shí)間長(zhǎng)超過周期時(shí)間固蛾,下次任務(wù)會(huì)在該次任務(wù)執(zhí)行完之后趾诗,計(jì)算執(zhí)行延時(shí)(再等延遲一個(gè) period 的時(shí)長(zhǎng))郑兴。

2.3犀斋、線程池 API - Executors 工具類

你也可以自己實(shí)例化線程池,也可以用 Executors 創(chuàng)建線程池的工廠類情连,常用方法如下:

1) newFixedThreadPool(int nThreads)

創(chuàng)建一個(gè)固定大小叽粹、任務(wù)隊(duì)列無界的線程池。核心線程數(shù) = 最大線程數(shù)却舀。

2) newCachedThreadPool()

創(chuàng)建一個(gè)大小無界的緩存線程池虫几。他的任務(wù)隊(duì)列是一個(gè)同步隊(duì)列。
任務(wù)加入到池中挽拔,如果池中有空閑線程辆脸,則用空閑線程執(zhí)行,如無則創(chuàng)建新的線程執(zhí)行螃诅,池中的線程空閑超過60秒啡氢,將被銷毀釋放。
線程數(shù)隨任務(wù)的多少變化州刽。適用于任務(wù)量不可控空执,且執(zhí)行耗時(shí)較小的異步任務(wù)。
核心線程數(shù) = 0穗椅, 最大線程數(shù) = Integer.MAX_VALUE

3) newSingleThreadExecutor()

只有一個(gè)線程來執(zhí)行無界任務(wù)隊(duì)列的單一線程池辨绊。該線程池確保任務(wù)按照加入隊(duì)列的順序一個(gè)一個(gè)一次執(zhí)行。
當(dāng)唯一的線程因任務(wù)異常終止時(shí)匹表,將創(chuàng)建一個(gè)新的線程來執(zhí)行后續(xù)的任務(wù)门坷。
與 newFixedThreadPool(1) 的區(qū)別在于,單一線程池的大小在 new SingleThreadExecutor 方法中硬編碼袍镀,不能再改變默蚌。

4) newScheduledThreadPool(int corePoolSize)

能定時(shí)執(zhí)行任務(wù)的線程池。該池的核心線程數(shù)由參數(shù)來指定苇羡,最大線程數(shù) = Integer.MAX_VALUE

3绸吸、線程池原理 - 任務(wù) execute 過程

1、是否達(dá)到核心線程數(shù)量设江?沒達(dá)到锦茁,創(chuàng)建一個(gè)工作線程來執(zhí)行任務(wù)。

2叉存、任務(wù)隊(duì)列是否已滿码俩?沒滿,則將新提交的任務(wù)存儲(chǔ)在任務(wù)隊(duì)列里邊歼捏。

3稿存、是否達(dá)到線程池最大數(shù)量笨篷?沒達(dá)到,則創(chuàng)建一個(gè)新的工作線程來執(zhí)行任務(wù)瓣履。

4率翅、最后,執(zhí)行拒絕策略來處理這個(gè)任務(wù)拂苹。

4安聘、線程數(shù)量

如何確定合適數(shù)量的線程?

計(jì)算型任務(wù):cpu數(shù)量的1~2倍瓢棒。

IO型任務(wù):根據(jù)具體的IO阻塞時(shí)長(zhǎng)進(jìn)行考量決定浴韭。

如 Tomcat 中默認(rèn)的最大線程數(shù)為:200

也可以考慮根據(jù)需要在一個(gè)最小數(shù)量和最大數(shù)量間自動(dòng)增減線程數(shù)。

監(jiān)控CPU的使用率脯宿,如果遠(yuǎn)小于80%則使用不合理念颈,大于也不可理,接近則表示使用良好连霉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末榴芳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子跺撼,更是在濱河造成了極大的恐慌窟感,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歉井,死亡現(xiàn)場(chǎng)離奇詭異柿祈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)哩至,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門躏嚎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人菩貌,你說我怎么就攤上這事卢佣。” “怎么了箭阶?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵虚茶,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我仇参,道長(zhǎng)嘹叫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任冈敛,我火速辦了婚禮,結(jié)果婚禮上鸣皂,老公的妹妹穿的比我還像新娘抓谴。我一直安慰自己暮蹂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布癌压。 她就那樣靜靜地躺著仰泻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪滩届。 梳的紋絲不亂的頭發(fā)上集侯,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音帜消,去河邊找鬼棠枉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛泡挺,可吹牛的內(nèi)容都是我干的辈讶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼娄猫,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼贱除!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起媳溺,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤月幌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后悬蔽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扯躺,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年屯阀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缅帘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡难衰,死狀恐怖钦无,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盖袭,我是刑警寧澤失暂,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站鳄虱,受9級(jí)特大地震影響弟塞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拙已,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一决记、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧倍踪,春花似錦系宫、人聲如沸索昂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽椒惨。三九已至,卻和暖如春潮罪,著一層夾襖步出監(jiān)牢的瞬間康谆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工嫉到, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沃暗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓屯碴,卻偏偏與公主長(zhǎng)得像描睦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子导而,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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

  • 線程池主要用來解決線程生命周期開銷問題和資源不足問題忱叭。通過對(duì)多個(gè)任務(wù)重復(fù)使用線程,線程創(chuàng)建的開銷就被分?jǐn)偟搅硕鄠€(gè)任...
    安仔夏天勤奮閱讀 1,023評(píng)論 0 10
  • 線程池中有一定數(shù)量的工作線程今艺,工作線程會(huì)循環(huán)從任務(wù)隊(duì)列中獲取任務(wù)韵丑,并執(zhí)行這個(gè)任務(wù)。那么怎么去停止這些工作線程呢虚缎?這...
    wo883721閱讀 1,625評(píng)論 0 14
  • 222
    Sean_9f73閱讀 210評(píng)論 0 0
  • 真實(shí)經(jīng)歷:在之前的項(xiàng)目中撵彻,UI小姐姐告訴我們一位前端小姐姐說我們項(xiàng)目蘋果手機(jī)中的邊框好像不是1像素的,比1像素粗实牡。...
    星飛822閱讀 525評(píng)論 0 0
  • 幾天前做了一個(gè)夢(mèng)陌僵。 我在老房子里,在跟爺爺一起睡的那張床上创坞,在爺爺身邊碗短。爺爺突然轉(zhuǎn)過身,抱著我题涨,一股爺爺?shù)南矶鴣?..
    怎一個(gè)強(qiáng)字了得閱讀 64評(píng)論 0 0