淺聊一下Java多線程:線程池

前言:當我們線程創(chuàng)建過多時州藕,容易引發(fā)內(nèi)存溢出森篷,這時我們?nèi)绾谓鉀Q這個問題呢?

一营罢、什么是線程池

顧名思義赏陵,線程池就是一個用來裝線程的池子(容器)。首先需要創(chuàng)建若干個可執(zhí)行的線程放入一個池中饲漾,有任務(wù)需要處理時蝙搔,會提交到線程池中的任務(wù)隊列,處理完之后線程并不會被銷毀能颁,而是仍然在線程池中等待下一個任務(wù)杂瘸。

二、線程池原理詳解

線程池原理圖

首先需要創(chuàng)建一個線程池伙菊,然后需要創(chuàng)建若干個可執(zhí)行的線程放入一個池中(Thread1-5)败玉,但是只開啟一部分默認的核心線程(例如Thread1-3),接下來有任務(wù)進入并且假設(shè)都長時間持續(xù)占有線程時镜硕,當只有幾個(這里如果是小于等于三個)任務(wù)時运翼,會按順序分配到三個核心線程中,如果大于三個則會進入到任務(wù)隊列(workQueue,Task4-7)中等待兴枯,如果任務(wù)超過了workQueue的最大容納量血淌,則創(chuàng)建新的線程(Thread4-5),并將workQueue中的任務(wù)按順序分別到線程中财剖,Task8-9進入workQueue悠夯,如果還有Task加入,那么調(diào)用拒絕策略方法躺坟,防止Task進入沦补;如果線程Thread4-5執(zhí)行完任務(wù)后在一定時間內(nèi)沒有任務(wù)進入,則會被回收咪橙。

三夕膀、線程池的優(yōu)點

因此,從上面的分析來看美侦,對比不使用線程池的情況(即創(chuàng)建線程對象产舞、執(zhí)行任務(wù)、釋放線程對象)菠剩,線程池具有以下優(yōu)點:

  • 降低資源消耗易猫。通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗。(前面的Task先執(zhí)行完后后面的Task可以復(fù)用前面的線程)
  • 提高響應(yīng)速度具壮。當任務(wù)到達時擦囊,任務(wù)可以不需要等到線程創(chuàng)建就能立即執(zhí)行违霞。(提前創(chuàng)建好核心線程Thread1-3)
  • 提高線程的可管理性。線程是稀缺資源瞬场,如果無限制的創(chuàng)建买鸽,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性贯被,使用線程池可以進行統(tǒng)一的分配眼五,調(diào)優(yōu)和監(jiān)控。

四彤灶、線程池的參數(shù)含義

首先看幼,我們來看源碼:

   Executor executor = new ThreadPoolExecutor( 
                                              CORE_POOL_SIZE,
                                              MAXIMUM_POOL_SIZE,
                                              KEEP_ALIVE,
                                              TimeUnit.SECONDS, 
                                              sPoolWorkQueue,
                                              sThreadFactory 
                                               );
    public ThreadPoolExecutor (int corePoolSize,
                               int maximumPoolSize,
                               long keepAliveTime,
                               TimeUnit unit,
                               BlockingQueue<Runnable workQueue>,
                               ThreadFactory threadFactory )
  • corePoolSize:核心線程數(shù)。默認情況下幌陕,核心線程會一直存活诵姜,但是當將 allowCoreThreadTimeout 設(shè)置為 true 時,核心線程也會超時回收搏熄。
  • maximumPoolSize:線程池所能容納的最大線程數(shù)棚唆。當活躍線程數(shù)達到該數(shù)值后,后續(xù)的新任務(wù)將會阻塞心例。
  • keepAliveTime:線程閑置超時時長荔烧。如果超過該時長楚午,非核心線程就會被回收峡碉。
  • unit:指定 keepAliveTime 參數(shù)的時間單位葛虐。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)译株、TimeUnit.MINUTES(分)瓜喇。
  • workQueue:任務(wù)隊列。通過線程池的 execute() 方法提交的 Runnable 對象將存儲在該參數(shù)中歉糜。其采用阻塞隊列實現(xiàn)乘寒。
  • threadFactory(可選):線程工廠。用于指定為線程池創(chuàng)建新線程的方式现恼。
  • handler(可選):拒絕策略。當達到最大線程數(shù)時需要執(zhí)行的飽和策略黍檩。

五叉袍、線程池的使用流程

// 創(chuàng)建線程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,
                                             MAXIMUM_POOL_SIZE,
                                             KEEP_ALIVE,
                                             TimeUnit.SECONDS,
                                             sPoolWorkQueue,
                                             sThreadFactory);
// 向線程池提交任務(wù)
threadPool.execute(new Runnable() {
    @Override
    public void run() {
        ... // 線程執(zhí)行的任務(wù)
    }
});
// 關(guān)閉線程池
threadPool.shutdown(); // 設(shè)置線程池的狀態(tài)為SHUTDOWN,然后中斷所有沒有正在執(zhí)行任務(wù)的線程
threadPool.shutdownNow(); // 設(shè)置線程池的狀態(tài)為 STOP刽酱,然后嘗試停止所有的正在執(zhí)行或暫停任務(wù)的線程喳逛,并返回等待執(zhí)行任務(wù)的列表

六、常見線程池

  1. 定長線程池(FixedThreadPool):只有核心線程棵里,線程數(shù)量固定润文,執(zhí)行完立即回收姐呐,任務(wù)隊列為鏈表結(jié)構(gòu)的有界隊列。
  2. 定時線程池(ScheduledThreadPool):核心線程數(shù)量固定典蝌,非核心線程數(shù)量無限曙砂,執(zhí)行完閑置 10ms 后回收,任務(wù)隊列為延時阻塞隊列骏掀。
  3. 可緩存線程池(CachedThreadPool):無核心線程鸠澈,非核心線程數(shù)量無限,執(zhí)行完閑置 60s 后回收截驮,任務(wù)隊列為不存儲元素的阻塞隊列笑陈。
  4. 單線程化線程池(SingleThreadExecutor):只有 1 個核心線程,無非核心線程葵袭,執(zhí)行完立即回收涵妥,任務(wù)隊列為鏈表結(jié)構(gòu)的有界隊列。

七坡锡、拒絕策略

  1. AbortPolicy(默認):丟棄任務(wù)并拋出 RejectedExecutionException 異常蓬网。
  2. CallerRunsPolicy:由調(diào)用線程處理該任務(wù)。
  3. DiscardPolicy:丟棄任務(wù)娜氏,但是不拋出異常拳缠。可以配合這種模式進行自定義的處理方式贸弥。
  4. DiscardOldestPolicy:丟棄隊列最早的未處理任務(wù)窟坐,然后重新嘗試執(zhí)行任務(wù)。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绵疲,一起剝皮案震驚了整個濱河市哲鸳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盔憨,老刑警劉巖徙菠,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異郁岩,居然都是意外死亡婿奔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門问慎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萍摊,“玉大人,你說我怎么就攤上這事如叼”荆” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長踊沸。 經(jīng)常有香客問我歇终,道長,這世上最難降的妖魔是什么逼龟? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任评凝,我火速辦了婚禮,結(jié)果婚禮上审轮,老公的妹妹穿的比我還像新娘肥哎。我一直安慰自己,他們只是感情好疾渣,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布篡诽。 她就那樣靜靜地躺著,像睡著了一般榴捡。 火紅的嫁衣襯著肌膚如雪杈女。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天吊圾,我揣著相機與錄音达椰,去河邊找鬼。 笑死项乒,一個胖子當著我的面吹牛啰劲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播檀何,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蝇裤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了频鉴?” 一聲冷哼從身側(cè)響起栓辜,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎垛孔,沒想到半個月后藕甩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡周荐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年狭莱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片概作。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡腋妙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出仆嗦,到底是詐尸還是另有隱情辉阶,我是刑警寧澤先壕,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布瘩扼,位于F島的核電站谆甜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏集绰。R本人自食惡果不足惜规辱,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望栽燕。 院中可真熱鬧罕袋,春花似錦、人聲如沸碍岔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蔼啦。三九已至榆纽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捏肢,已是汗流浹背奈籽。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鸵赫,地道東北人衣屏。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像辩棒,于是被迫代替她去往敵國和親狼忱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

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