Java線程池

線程池的優(yōu)勢(shì):

  1. 通過復(fù)用已有的線程法精,降低線程創(chuàng)建的銷毀的系統(tǒng)開銷
  2. 提高響應(yīng)速度多律,復(fù)用已有的線程避免了創(chuàng)建線程的開銷
  3. 方便線程數(shù)量的管控,如果創(chuàng)建的線程過多搂蜓,咋可能導(dǎo)致系統(tǒng)化新能的下降或者oom的發(fā)生狼荞。、
  4. 線程池提供了定時(shí)等功能帮碰,并且方便創(chuàng)建

我們可以使用new ThreadPoolExecutor()來創(chuàng)建一個(gè)線程池

    public ThreadPoolExecutor(
          int corePoolSize,
          int maximumPoolSize,
          long keepAliveTime,
          TimeUnit unit,
          BlockingQueue<Runnable> workQueue,
          ThreadFactory threadFactory,
          RejectedExecutionHandler handler)
  1. corePoolSize 這個(gè)參數(shù)意思是核心線程的數(shù)量相味,他們一直存在于線程池中,即使處于閑置狀態(tài)也不會(huì)被銷毀殉挽,除非設(shè)置了allowCoreThreadTimeOut這個(gè)參數(shù)丰涉,則在閑置狀態(tài)超過了這個(gè)參數(shù)keepAliveTime 則被銷毀
  2. maximumPoolSize 線程池中的最大線程數(shù)量,如果活動(dòng)的線程數(shù)超過這個(gè)值的話斯碌,后續(xù)的線程就會(huì)被阻塞一死。 最大數(shù)量指的是核心線程數(shù)量和非核心線程數(shù)量
  3. keepAliveTime 非核心線程閑置存在的時(shí)長,意思當(dāng)非核心線程閑置時(shí)間超過這個(gè)值就會(huì)被回收
  4. TimeUnit 是keepAliveTime的時(shí)間單位傻唾,是個(gè)枚舉類型投慈,包含TimeUnit.MILLISECONDS 毫秒,SECONDS秒冠骄,天等等
  5. workQueue 阻塞隊(duì)列伪煤。 所有提交的Runnable線程都存放到該隊(duì)列中,常用的阻塞隊(duì)列有:
    image
  6. threadFactory 線程 工廠凛辣,為線程池提供線程的創(chuàng)建抱既,一般使用默認(rèn)的即可Executors.defaultThreadFactory()
  7. handler 當(dāng)任務(wù)隊(duì)列已滿,并且線程池達(dá)到了最大線程數(shù)的時(shí)候規(guī)定了接下來的線程該如何處理蟀给。
    image

    ThreadPoolExecutor提供了多鐘構(gòu)造方法蝙砌,我們可以使用他默認(rèn)的一些方法來創(chuàng)建,比如:
ThreadPoolExecutor executor = new   
ThreadPoolExecutor(  
10, 10, 1000, TimeUnit.SECONDS,  
new LinkedBlockingDeque<>());

ThreadPoolExecutor 提供了execute和submit兩個(gè)方法提交線程任務(wù)跋理,比如:

        executor.submit(()->{});
        executor.execute(()->{});

但是submit提供了一分返回值择克,所以如果們用Callable的話,那么我們就可以獲得一個(gè)返回值前普,如果不知道Callable請(qǐng)看我的另外一篇文章 《Java第三種線程創(chuàng)建方法》

    Future<String> submit = executor.submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
            return "";
        }
    });
    
    submit.get();
    如果使用Lambda更簡單:
    Future<String> submit = executor.submit(() -> "")

submit.get(); 可以得到call中返回的值肚邢。

其實(shí)系統(tǒng)為我們提供了集中線程池的創(chuàng)建,所以不用直接使用ThreadPoolExecutor這個(gè)類來創(chuàng)建線程池:

newFixedThreadPool

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

newFixedThreadPool,固定線程數(shù)量的線程池骡湖,核心線程池?cái)?shù)和非核心線程數(shù)量相等并且由自己定義贱纠,不存在超時(shí)機(jī)制,任務(wù)隊(duì)列理論是上可以無限大

newCachedThreadPool

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

可以看到 核心線程數(shù)為0响蕴,而線程池的最大數(shù)量可以認(rèn)為無限大谆焊,超時(shí)時(shí)間60秒,并且是不緩存線程的SynchronousQueue隊(duì)列浦夷,所以可以來多少線程就去執(zhí)行多少線程辖试,沒有任務(wù)了60秒之后就全部銷毀

ScheduledExecutorService

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

定時(shí)執(zhí)行線程任務(wù)的線程池:核心線程數(shù)由自己定義,最大線程數(shù)量為無限大劈狐,超時(shí)間為0秒罐孝,所以非核心線程閑置立刻被銷毀,用到了延遲隊(duì)列肥缔,可以設(shè)置線程延遲多少時(shí)間執(zhí)行莲兢,或者多長時(shí)間重復(fù)一次,比如:

scheduledExecutorService.schedule(() -> {}, 10, TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(()->{}, 20, 10, TimeUnit.SECONDS);

第一表示10秒之后執(zhí)行線程续膳,第二個(gè)表示20秒之后每10秒執(zhí)行一次線程

newSingleThreadExecutor

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

可以看到核心線程數(shù)和最大線程數(shù)都是1改艇,其實(shí)就是單線程了,所以也就不用考慮并發(fā)啊什么的了姑宽。

線程池的執(zhí)行過程

線程池執(zhí)行的過程也挺有意思:

  1. 提交一個(gè)線程遣耍,如果核心線程數(shù)量沒有滿的話,就啟動(dòng)一個(gè)線程來執(zhí)行炮车。
  2. 如果核心線程已滿,那么就插入到阻塞隊(duì)列里面去
  3. 如果阻塞隊(duì)列已經(jīng)滿的話酣溃,就啟動(dòng)一個(gè)非核心線程
  4. 如果非核心線程也滿了瘦穆,那就調(diào)用handler,報(bào)異成尥悖或者給替換掉了
    原本我以為扛或,如果核心線程已滿,就會(huì)立即啟動(dòng)非核心線程來執(zhí)行線程碘饼,實(shí)際上是加到阻塞隊(duì)列里面熙兔,只有阻塞隊(duì)列滿了之后,才會(huì)啟動(dòng)非核心線程艾恼∽∩妫可以簡單的舉個(gè)例子:
ThreadPoolExecutor service = new ThreadPoolExecutor(2, 10,   
1000, TimeUnit.SECONDS, new LinkedBlockingDeque<>());

service.execute(() -> {
    try {
        Thread.sleep(2000);
        System.out.println(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
service.execute(() -> {
    try {
        Thread.sleep(2000);
        System.out.println(2);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
service.execute(() -> {
    System.out.println(3);
});

上面定義了一個(gè)2個(gè)核心線程數(shù)量和2個(gè)非核心線程數(shù)量的線程池,然后提交3個(gè)線程钠绍,前兩個(gè)沉睡2秒舆声,結(jié)果總是:1 3 2
所以是等到核心線程執(zhí)行結(jié)束又執(zhí)行的第3個(gè)線程。
那么對(duì)于ScheduledExecutorService 這個(gè)線程池如果也是符合這個(gè)理論的話,豈不是設(shè)置的定時(shí)可能永遠(yuǎn)不會(huì)執(zhí)行到了么媳握? 我們做個(gè)試驗(yàn):

ScheduledExecutorService service = Executors.newScheduledThreadPool(10);

service.schedule(()->{

    try {
        Thread.sleep(3000);
        System.out.println(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}, 0, TimeUnit.MILLISECONDS );


service.schedule(()->{

    try {
        Thread.sleep(3000);
        System.out.println(2);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}, 0, TimeUnit.MILLISECONDS );

service.schedule(()-> System.out.println(3), 1000, TimeUnit.MILLISECONDS );

但是結(jié)果卻始終是 3 1 2. 所以對(duì)于這個(gè)定時(shí)的線程池來說這個(gè)理論并不符合

最后當(dāng)應(yīng)用退出碱屁,別忘了關(guān)系線程池:

    service.shutdown();
    service.shutdownNow();
    service.isShutdown();

其中isShutdown表示線程池關(guān)閉是否完成。
shutdown 表示中斷所有沒有執(zhí)行的線程任務(wù)
shutdownNow表示中斷執(zhí)行所有任務(wù)線程蛾找,包括正在執(zhí)行的線程娩脾,他會(huì)有一個(gè)返回值,返回的是那些沒有執(zhí)行的線程列表

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末打毛,一起剝皮案震驚了整個(gè)濱河市柿赊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隘冲,老刑警劉巖闹瞧,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異展辞,居然都是意外死亡奥邮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門罗珍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洽腺,“玉大人,你說我怎么就攤上這事覆旱≌号螅” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵扣唱,是天一觀的道長藕坯。 經(jīng)常有香客問我,道長噪沙,這世上最難降的妖魔是什么炼彪? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮正歼,結(jié)果婚禮上辐马,老公的妹妹穿的比我還像新娘。我一直安慰自己局义,他們只是感情好喜爷,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著萄唇,像睡著了一般檩帐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上穷绵,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天轿塔,我揣著相機(jī)與錄音,去河邊找鬼。 笑死勾缭,一個(gè)胖子當(dāng)著我的面吹牛揍障,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俩由,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼毒嫡,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了幻梯?” 一聲冷哼從身側(cè)響起兜畸,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎碘梢,沒想到半個(gè)月后咬摇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡煞躬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年肛鹏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恩沛。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡在扰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出雷客,到底是詐尸還是另有隱情芒珠,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布搅裙,位于F島的核電站皱卓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏部逮。R本人自食惡果不足惜好爬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望甥啄。 院中可真熱鬧,春花似錦炬搭、人聲如沸蜈漓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽融虽。三九已至,卻和暖如春灼芭,著一層夾襖步出監(jiān)牢的瞬間有额,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巍佑,地道東北人茴迁。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像萤衰,于是被迫代替她去往敵國和親堕义。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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

  • 線程池是什么脆栋? 線程池用于多線程處理中倦卖,它可以根據(jù)系統(tǒng)的情況,可以有效控制線程執(zhí)行的數(shù)量椿争,優(yōu)化運(yùn)行效果怕膛。線程池做的...
    懶癌正患者閱讀 2,740評(píng)論 2 80
  • 本文已獨(dú)家授權(quán) 鴻洋( hongyangAndroid) 公眾號(hào)發(fā)布! 前言: 本篇文章主要介紹的是Java(...
    騎小豬看流星閱讀 32,136評(píng)論 36 340
  • 一.Java中的ThreadPoolExecutor類 java.uitl.concurrent.ThreadPo...
    誰在烽煙彼岸閱讀 645評(píng)論 0 0
  • 4 地鐵快速行進(jìn)的聲音因?yàn)檐噹飵缀鯖]有乘客而顯得特別的生冷秦踪。 柏曉雯又看了看老人褐捻。老人仍舊保持著剛才的姿勢(shì),一動(dòng)...
    北岸夜雨閱讀 3,500評(píng)論 1 3
  • 我們都讀過紀(jì)伯倫的那首詩洋侨,孩子是分離的獨(dú)立個(gè)體舍扰,要尊重孩子的生命體驗(yàn)。但要真正的做到希坚,何其難也边苹。 七七...
    筱荀閱讀 298評(píng)論 0 0