ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
4, // corePoolSize
64, // maximumPoolSize
60L, // keepAliveTime
TimeUnit.SECONDS, // timeUnit
new LinkedBlockingQueue<>(100000) // workQueue
);
我們有時候會使用上述的代碼來新建一個ThreadPoolExecutor對象,使用LinkedBlockingQueue
作爲workQueue。
需要特別注意的是,上述創建的ThreadPoolExecutor對象,當同時有64個任務進來時,並不會創建64個線程來同時處理這64個任務,而只創建4個core線程優先處理最先進來的4個任務,將後進來的60個任務放入LinkedBlockingQueue隊列中,隊列中的任務排隊等待被這4個core線程處理。
使用LinkedBlockingQueue
作爲workQueue,ThreadPoolExecutor對象在隊列不滿的情況下只會創建core線程,不會創建非core線程,設置的maximumPoolSize
並不起作用。
原因分析
下述代碼是ThreadPoolExecutor的execute方法,其中描述了新建線程的機制。可以發現只有當滿足下面的兩個條件之一時,纔會新建線程:
- 當前存活的線程數小於corePoolSize;(新建core線程)
- 往workQueue添加元素失敗;(新建非core線程)
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) { // 條件1:存活線程小於corePoolSize,新建core線程
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0) // 正常情況下,這裏的條件不會滿足
addWorker(null, false);
}
else if (!addWorker(command, false)) // 條件2:往隊列添加元素失敗,新建非core線程
reject(command);
}
可以發現能新建非core線程的直接原因是隊列workQueue添加元素失敗,因此選擇不同的BlockingQueue實現類會對新建線程產生很大的影響,常用的BlockingQueue:
- LinkedBlockingQueue:隊列已滿時會添加失敗;
- SynchronousQueue:如果沒有其他線程在等待獲取元素時會添加失敗;