線程池

[TOC]

線程池

1. 并發(fā)隊(duì)列:阻塞隊(duì)列和非阻塞隊(duì)列

區(qū)別如下:

入隊(duì):
  • 非阻塞隊(duì)列:當(dāng)隊(duì)列中滿了的時(shí)候,放入數(shù)據(jù)铭腕,數(shù)據(jù)丟失
  • 阻塞隊(duì)列:當(dāng)隊(duì)列滿了的時(shí)候,進(jìn)行等待,什么時(shí)候隊(duì)列中有出隊(duì)的數(shù)據(jù)谴餐,那么第 11 個(gè)再放進(jìn)入
出隊(duì):
  • 非阻塞隊(duì)列:如果現(xiàn)在隊(duì)列中沒有元素,取數(shù)據(jù)呆抑,得到的是 null
  • 阻塞隊(duì)列:等待岂嗓,什么時(shí)候放進(jìn)去,再取出來

線程池是使用阻塞隊(duì)列鹊碍。


2. 線程池原理:ThreadPoolExecutor 底層原理解析

2. 1線程的生命周期

從出生到死亡的階段厌殉。

2.2 線程池工作原理
ThreadPoolExecutor t = new ThreadPoolExecutor(1, 3, 0, TimeUnit.MICROSECONDS, new LinkedBlockingDeque<>(3));

參數(shù)含義:

  • 1:核心線程數(shù)
  • 3:最大線程數(shù)
  • 0 和 TimeUnit.MICROSECONDS:當(dāng)任務(wù)量大于隊(duì)列長(zhǎng)度需要?jiǎng)?chuàng)建線程的時(shí)候食绿,新創(chuàng)建的這個(gè)線程假如把隊(duì)列的任務(wù)都執(zhí)行完了,那么等待新任務(wù)的空閑時(shí)間就是這個(gè)
  • new LinkedBlockingDeque<>(3)):阻塞隊(duì)列:
    • 方法有參數(shù):隊(duì)列長(zhǎng)度為 3
    • 方法無參數(shù):隊(duì)列長(zhǎng)度為 Integer.MAX_VALUE

執(zhí)行流程圖如下所示:

2.3 舉個(gè)例子
package com.test.jdk8;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThreadPoolExecutor {

    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3));
        // 利用線程池里的線程公罕,開始執(zhí)行任務(wù)
        // 執(zhí)行第一個(gè)任務(wù)
        pool.execute(new TestThread());
        // 執(zhí)行下面三個(gè)任務(wù)器紧,放入阻塞隊(duì)列,阻塞隊(duì)列滿:
        pool.execute(new TestThread());
        pool.execute(new TestThread());
        pool.execute(new TestThread());

        // 執(zhí)行第 4個(gè)任務(wù)楼眷,創(chuàng)建新線程铲汪,分?jǐn)側(cè)蝿?wù)
        pool.execute(new TestThread());

        // 執(zhí)行第 5 個(gè)任務(wù),創(chuàng)建新創(chuàng)建罐柳,線程數(shù)大于最大線程數(shù)掌腰,報(bào)錯(cuò)
        pool.execute(new TestThread());


        // 關(guān)閉線程池
        pool.shutdown();
    }

}

class TestThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

3. 線程池的分類

1. newCachedThreadPool 可緩存線程池

創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過處理需要张吉,可靈活回收空閑線程齿梁,若無可回收,則新建線程芦拿。示例代碼如下:

package ThreadTest;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {

    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool();

        for (int i = 0; i < 100; i++) {
            // lambda 表達(dá)式, 實(shí)現(xiàn) new Runnable() 的 run() 方法
            es.execute(() -> System.out.println(Thread.currentThread().getName()));
        }

        es.shutdown();

    }

}

查看 newCachedThreadPool 源碼士飒,可知:

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

該線程池的核心線程數(shù)為 0, 最大線程數(shù)為 Integer.MAX_VALUE蔗崎,將會(huì)根據(jù)需要?jiǎng)?chuàng)建新線程酵幕,新線程的數(shù)量不大于 Integer.MAX_VALUE,線程執(zhí)行任務(wù)結(jié)束后被釋放可重復(fù)使用該線程執(zhí)行另一個(gè)任務(wù)缓苛。

部分執(zhí)行結(jié)果如下:

pool-1-thread-6
pool-1-thread-11
pool-1-thread-6
pool-1-thread-10
pool-1-thread-4
pool-1-thread-11
pool-1-thread-2
2. newFixedThreadPool 定長(zhǎng)線程池

創(chuàng)建一個(gè)定長(zhǎng)線程池芳撒,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待未桥。示例代碼如下:

package ThreadTest;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {

    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 100; i++) {
            // lambda 表達(dá)式, 實(shí)現(xiàn) new Runnable() 的 run() 方法
            es.execute(() -> System.out.println(Thread.currentThread().getName()));
        }

        es.shutdown();

    }

}

查看 newFixedThreadPool 源碼笔刹,可知:

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

傳入的參數(shù)即為核心線程數(shù)和最大線程數(shù),核心線程數(shù)和最大線程數(shù)的數(shù)量是相等的冬耿。

所以上述示例代碼的執(zhí)行結(jié)果的線程數(shù)就為 3舌菜,部分執(zhí)行結(jié)果如下:

pool-1-thread-1
pool-1-thread-3
pool-1-thread-2
pool-1-thread-3
pool-1-thread-1
3. newScheduledThreadPool 定時(shí)線程池

創(chuàng)建一個(gè)定時(shí)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行亦镶。延遲執(zhí)行示例代碼如下:

package ThreadTest;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test {

    public static void main(String[] args) {
        ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);

        for (int i = 0; i < 100; i++) {
            ses.schedule(() -> System.out.println(Thread.currentThread().getName()), 3, TimeUnit.SECONDS);
        }

        ses.shutdown();

    }
}

查看 newScheduledThreadPool 源碼日月,如下:

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

可知,newScheduledThreadPool 傳入的參數(shù)即為核心線程數(shù)缤骨,最大線程數(shù)為 Integer.MAX_VALUE爱咬。

上述代碼通過設(shè)置延遲參數(shù) 3, 單位 TimeUnit.SECONDS绊起,延遲三秒后執(zhí)行任務(wù)精拟,創(chuàng)建的線程數(shù)為 2。執(zhí)行部分結(jié)果如下:

pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
4. newSingleThreadExecutor 單例線程池

創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù)蜂绎,保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行栅表。示例代碼如下:

package ThreadTest;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {

    public static void main(String[] args) {
        ExecutorService es = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 100; i++) {
            es.execute(() -> System.out.println(Thread.currentThread().getName()));
        }

        es.shutdown();

    }
}

查看 newSingleThreadExecutor 源碼,可知:

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

核心線程數(shù)和最大線程數(shù)都為 1师枣,執(zhí)行完任務(wù)后線程的存活時(shí)間為 0谨读,即創(chuàng)建出來的線程只會(huì)執(zhí)行一次任務(wù),保證單例執(zhí)行坛吁。

運(yùn)行部分結(jié)果如下:

pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末劳殖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拨脉,更是在濱河造成了極大的恐慌哆姻,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玫膀,死亡現(xiàn)場(chǎng)離奇詭異矛缨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)帖旨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門箕昭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人解阅,你說我怎么就攤上這事落竹。” “怎么了货抄?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵述召,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我蟹地,道長(zhǎng)积暖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任怪与,我火速辦了婚禮夺刑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘分别。我一直安慰自己遍愿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布茎杂。 她就那樣靜靜地躺著错览,像睡著了一般纫雁。 火紅的嫁衣襯著肌膚如雪煌往。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音刽脖,去河邊找鬼羞海。 笑死,一個(gè)胖子當(dāng)著我的面吹牛曲管,可吹牛的內(nèi)容都是我干的却邓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼院水,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼腊徙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起檬某,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤撬腾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后恢恼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體民傻,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年场斑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了漓踢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡漏隐,死狀恐怖喧半,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情青责,我是刑警寧澤薯酝,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站爽柒,受9級(jí)特大地震影響吴菠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浩村,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一做葵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧心墅,春花似錦酿矢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至铐姚,卻和暖如春策肝,著一層夾襖步出監(jiān)牢的瞬間肛捍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國打工之众, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拙毫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓棺禾,卻偏偏與公主長(zhǎng)得像缀蹄,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膘婶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

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

  • 線程的兩種創(chuàng)建方式:繼承Thread類或者實(shí)現(xiàn)Runnable接口缺前,Thread類本質(zhì)上是實(shí)現(xiàn)了Runnable接...
    繁星追逐閱讀 594評(píng)論 0 1
  • 線程池主要用來解決線程生命周期開銷問題和資源不足問題。通過對(duì)多個(gè)任務(wù)重復(fù)使用線程悬襟,線程創(chuàng)建的開銷就被分?jǐn)偟搅硕鄠€(gè)任...
    安仔夏天勤奮閱讀 1,023評(píng)論 0 10
  • 前言 掌握線程池是后端程序員的基本要求诡延,相信大家求職面試過程中,幾乎都會(huì)被問到有關(guān)于線程池的問題古胆。我在網(wǎng)上搜集了幾...
    Jay_Wei閱讀 975評(píng)論 0 0
  • 前言 掌握線程池是后端程序員的基本要求肆良,相信大家求職面試過程中,幾乎都會(huì)被問到有關(guān)于線程池的問題逸绎。我在網(wǎng)上搜集了幾...
    勤奮的碼農(nóng)閱讀 1,287評(píng)論 0 1
  • 姥姥沒在家惹恃,昨晚回來簡(jiǎn)單的打掃了一下房間,我們就睡覺了棺牧。 你和爸爸一覺睡到九點(diǎn)鐘巫糙,我們一起去喝豆腐湯。你好久沒喝了...
    素面迎風(fēng)閱讀 118評(píng)論 0 0