阿里的面試官問了個問題,如果corePolllSize=10,MaxPollSize=20,如果來了25個線程 怎么辦?
答案:
當一個任務通過execute(Runnable)方法欲添加到線程池時:
1、如果此時線程池中的數量小於corePoolSize,即使線程池中的線程都處於空閑狀態,也要創建新的線程來處理被添加的任務。
2、如果此時線程池中的數量等於corePoolSize,但是緩沖隊列 workQueue未滿,那么任務被放入緩沖隊列。
3、如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,再有新的線程,開始增加線程池的線程數量處理新的線程,直到maximumPoolSize;
4、如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量等於maximumPoolSize,那么通過 handler所指定的策略來處理此任務。也就是:處理任務的優先級為:核心線程corePoolSize、任務隊列workQueue、最大線程 maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。
5、當線程池中的線程數量大於corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止。這樣線程池可以動態的調整池中的線程數。
當線程數小於corePoolSize時,提交一個任務創建一個線程(即使這時有空閑線程)來執行該任務。
當線程數大於等於corePoolSize,首選將任務添加等待隊列workQueue中(這里的workQueue是上面的BlockingQueue),等有空閑線程時,讓空閑線程從隊列中取任務。
當等待隊列滿時,如果線程數量小於maximumPoolSize則創建新的線程,否則使用拒絕線程處理器來處理提交的任務。
一:ThreadPoolExecutor的構造函數:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
ThreadPollExecutor中的所有的構造函數最終都會調用上面這個構造函數,接下來我們來分析一下這些參數的含義:
corePoolSize:線程池啟動后,在池中保持的線程的最小數量。需要說明的是線程數量是逐步到達corePoolSize值的。例如corePoolSize被設置為10,而任務數量只有5,則線程池中最多會啟動5個線程,而不是一次性地啟動10個線程。
maxinumPoolSize:線程池中能容納的最大線程數量,如果超出,則使用RejectedExecutionHandler拒絕策略處理。
keepAliveTime:線程的最大生命周期。這里的生命周期有兩個約束條件:一:該參數針對的是超過corePoolSize數量的線程;二:處於非運行狀態的線程。舉個例子:如果corePoolSize(最小線程數)為10,maxinumPoolSize(最大線程數)為20,而此時線程池中有15個線程在運行,過了一段時間后,其中有3個線程處於等待狀態的時間超過keepAliveTime指定的時間,則結束這3個線程,此時線程池中則還有12個線程正在運行。
unit:這是keepAliveTime的時間單位,可以是納秒,毫秒,秒,分鍾等。
workQueue:任務隊列。當線程池中的線程都處於運行狀態,而此時任務數量繼續增加,則需要一個容器來容納這些任務,這就是任務隊列。這個任務隊列是一個阻塞式的單端隊列。
newFixedThreadPool和newSingleThreadExector使用的是LinkedBlockingQueue的無界模式(美團面試題目)。
threadFactory:定義如何啟動一個線程,可以設置線程的名稱,並且可以確定是否是后台線程等。
handler:拒絕任務處理器。由於超出線程數量和隊列容量而對繼續增加的任務進行處理的程序。
ThreadPoolExecutor中的主要參數介紹完了。我們再說一下線程的管理過程:首先創建一個線程池,然后根據任務的數量逐步將線程增大到corePoolSize,如果此時仍有任務增加,則放置到workQueue中,直到workQueue爆滿為止,然后繼續增加池中的線程數量(增強處理能力),最終達到maxinumPoolSize。那如果此時還有任務要增加進來呢?這就需要handler來處理了,或者丟棄新任務,或者拒絕新任務,或者擠占已有的任務(拒絕策略,美團面試)。在任務隊列和線程池都飽和的情況下,一旦有線程處於等待(任務處理完畢,沒有新任務)狀態的時間超過keepAliveTime,則該線程終止,也就是說池中的線程數量會逐漸降低,直至為corePoolSize數量為止。
總結:
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue
RejectedExecutionHandler handler)
corePoolSize: 線程池維護線程的最少線程數,也是核心線程數,包括空閑線程
maximumPoolSize: 線程池維護線程的最大線程數
keepAliveTime: 線程池維護線程所允許的空閑時間
unit: 程池維護線程所允許的空閑時間的單位
workQueue: 線程池所使用的緩沖隊列
handler: 線程池對拒絕任務的處理策略