Java有幾種常見的線程池

注:本文目的在于整理線程池相關(guān)知識(shí),避免面試時(shí)不知道該說什么。

1. 四種線程池

1.1 NewCachedThreadPool
創(chuàng)建一個(gè)可緩存的線程池。如果線程池的大小超過了處理任務(wù)所需要的線程,那么就會(huì)回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時(shí),此線程池又可以智能的添加新線程來處理任務(wù)。此線程池不會(huì)對線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。
適用:執(zhí)行很多短期的任務(wù)

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

1.2 NewFixedThreadPool
創(chuàng)建一個(gè)指定工作線程數(shù)量的線程池。每當(dāng)提交一個(gè)任務(wù)就創(chuàng)建一個(gè)工作線程,如果工作線程數(shù)量達(dá)到線程池初始的最大數(shù),則將提交的任務(wù)存入到池隊(duì)列中。線程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會(huì)補(bǔ)充一個(gè)新線程。
適用:執(zhí)行長期運(yùn)行任務(wù)

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

1.3 NewSingleThreadExecutor
創(chuàng)建一個(gè)單線程化的Executor,即只創(chuàng)建唯一的工作者線程來執(zhí)行任務(wù),它只會(huì)用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO、LIFO、優(yōu)先級)執(zhí)行。如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線程來替代它。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。
適用:一個(gè)任務(wù)一個(gè)任務(wù)的執(zhí)行場景

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

1.4 NewScheduledThreadPool
創(chuàng)建一個(gè)大小無限的線程池。此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。
適用:周期性執(zhí)行任務(wù)的場景

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
}
// super()
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
 }

2. Java 線程池底層調(diào)用是什么?

2.1 以上這幾種線程池,都是調(diào)用的ThreadPoolExecutor類;而ThreadPoolExecutor類是ExecutorService接口的默認(rèn)實(shí)現(xiàn)之一。
2.2 構(gòu)造方法:

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
}

2.3 構(gòu)造方法參數(shù)定義:
corePoolSize:線程池中核心線程數(shù)的最大值
maximumPoolSize:線程池中能擁有最多線程數(shù)
keepAliveTime:線程存活時(shí)間,表示線程沒有任務(wù)執(zhí)行時(shí)最多保持多久時(shí)間會(huì)終止。默認(rèn)情況下,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí),keepAliveTime才會(huì)起作用,直到線程池中的線程數(shù)不大于corePoolSize
unit:時(shí)間單位
workQueue:用于緩存任務(wù)的阻塞隊(duì)列
threadFactory:線程工廠,主要用來創(chuàng)建線程;
defaultHandler:表示當(dāng)拒絕處理任務(wù)時(shí)的策略

2.4 corePoolSize、maximumPoolSize、workQueue三者之間的關(guān)系:
A.如果沒有空閑的線程執(zhí)行該任務(wù)并且當(dāng)前運(yùn)行線程數(shù)小于corePoolSize,則添加新的線程執(zhí)行該任務(wù)。
B.如果沒有空閑的線程執(zhí)行該任務(wù)并且當(dāng)前運(yùn)行線程數(shù)等于corePoolSize,同時(shí)阻塞隊(duì)列未滿,則將任務(wù)入隊(duì),而不添加新的線程。
C.如果沒有空閑的線程執(zhí)行該任務(wù)且阻塞隊(duì)列已滿同時(shí)線程池中的線程數(shù)小于maximumPoolSize,則創(chuàng)建此線程執(zhí)行任務(wù)。
D.如果沒有空閑的線程執(zhí)行該任務(wù)且阻塞隊(duì)列已滿同線程池中的線程數(shù)等于maximumPoolSize,則調(diào)用構(gòu)造函數(shù)中的handler指定的策略來拒絕新的任務(wù)。
E.另外,當(dāng)池子的線程數(shù)大于corePoolSize的時(shí)候,多余的線程會(huì)等待keepAliveTime長的時(shí)間,如果無請求可處理就自行銷毀。其會(huì)優(yōu)先創(chuàng)建 CorePoolSiz 線程, 當(dāng)繼續(xù)增加線程時(shí),先放入Queue中,當(dāng) CorePoolSiz 和 Queue 都滿的時(shí)候,就增加創(chuàng)建新線程,當(dāng)線程達(dá)到MaxPoolSize的時(shí)候,就會(huì)拋出錯(cuò) 誤 org.springframework.core.task.TaskRejectedException

3. ThreadPoolExecutor參數(shù)中的拒絕策略是什么?

ThreadPoolExecutor中默認(rèn)的拒絕策略為AbortPolicy。
3.1 AbortPolicy
ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。
這是線程池默認(rèn)的拒絕策略,在任務(wù)不能再提交的時(shí)候,拋出異常,及時(shí)反饋程序運(yùn)行狀態(tài)。如果是比較關(guān)鍵的業(yè)務(wù),推薦使用此拒絕策略,這樣子在系統(tǒng)不能承載更大的并發(fā)量的時(shí)候,能夠及時(shí)的通過異常發(fā)現(xiàn)。
3.2 DiscardPolicy
ThreadPoolExecutor.DiscardPolicy:丟棄任務(wù),但是不拋出異常。如果線程隊(duì)列已滿,則后續(xù)提交的任務(wù)都會(huì)被丟棄,且是靜默丟棄。
使用此策略,可能會(huì)使我們無法發(fā)現(xiàn)系統(tǒng)的異常狀態(tài)。建議是一些無關(guān)緊要的業(yè)務(wù)采用此策略。例如,本人的博客網(wǎng)站統(tǒng)計(jì)閱讀量就是采用的這種拒絕策略。
3.3 DiscardOldestPolicy
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù),然后重新提交被拒絕的任務(wù)。
此拒絕策略,是一種喜新厭舊的拒絕策略。是否要采用此種拒絕策略,還得根據(jù)實(shí)際業(yè)務(wù)是否允許丟棄老任務(wù)來認(rèn)真衡量。
3.4 CallerRunsPolicy
ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù),如果任務(wù)被拒絕了,則由調(diào)用線程(提交任務(wù)的線程)直接執(zhí)行此任務(wù)。

4. ThreadPoolExecutor參數(shù)中的隊(duì)列有幾種實(shí)現(xiàn)?

4.1 LinkedBlockingQueue是一個(gè)無界緩存等待隊(duì)列。 當(dāng)前執(zhí)行的線程數(shù)量達(dá)到corePoolSize的數(shù)量時(shí),剩余的元素會(huì)在阻塞隊(duì)列里等待。(所以在使用此阻塞隊(duì)列時(shí)maximumPoolSizes就相當(dāng)于無效了),每個(gè)線程完全獨(dú)立于其他線程。生產(chǎn)者和消費(fèi)者使用獨(dú)立的鎖來控制數(shù)據(jù)的同步,即在高并發(fā)的情況下可以并行操作隊(duì)列中的數(shù)據(jù)。
4.2 ArrayBlockingQueue是一個(gè)有界緩存等待隊(duì)列,可以指定緩存隊(duì)列的大小,當(dāng)正在執(zhí)行的線程數(shù)等于corePoolSize時(shí),多余的元素緩存在ArrayBlockingQueue隊(duì)列中等待有空閑的線程時(shí)繼續(xù)執(zhí)行,當(dāng)ArrayBlockingQueue已滿時(shí),加入ArrayBlockingQueue失敗,會(huì)開啟新的線程去執(zhí)行,當(dāng)線程數(shù)已經(jīng)達(dá)到最大的maximumPoolSizes時(shí),再有新的元素嘗試加入ArrayBlockingQueue時(shí)會(huì)報(bào)錯(cuò)
4.3 SynchronousQueue沒有容量,是無緩沖等待隊(duì)列,是一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列,會(huì)直接將任務(wù)交給消費(fèi)者,必須等隊(duì)列中的添加元素被消費(fèi)后才能繼續(xù)添加新的元素。擁有公平(FIFO)和非公平(LIFO)策略,非公平側(cè)羅會(huì)導(dǎo)致一些數(shù)據(jù)永遠(yuǎn)無法被消費(fèi)的情況。使用SynchronousQueue阻塞隊(duì)列一般要求maximumPoolSizes為無界,避免線程拒絕執(zhí)行操作。
4.4 DelayedWorkQueue是一個(gè)延遲任務(wù)的阻塞等待隊(duì)列

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容