面試突擊:說一下線程池七個參數(shù)的含義?
所謂的線程池的 7 大參數(shù)是指,在使用 ThreadPoolExecutor 創(chuàng)建線程池時所設(shè)置的 7 個參數(shù),如以下源碼所示:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
//...
}
這 7 個參數(shù)分別是:
- corePoolSize:核心線程數(shù)。
- maximumPoolSize:最大線程數(shù)。
- keepAliveTime:空閑線程存活時間。
- TimeUnit:時間單位。
- BlockingQueue:線程池任務(wù)隊列。
- ThreadFactory:創(chuàng)建線程的工廠。
- RejectedExecutionHandler:拒絕策略。
參數(shù)1:corePoolSize核
心線程數(shù):是指線程池中長期存活的線程數(shù)。
這就好比古代大戶人家,會長期雇傭一些“長工”來給他們干活,這些人一般比較穩(wěn)定,無論這一年的活多活少,這些人都不會被辭退,都是長期生活在大戶人家的。
參數(shù)2:maximumPoolSize
最大線程數(shù):線程池允許創(chuàng)建的最大線程數(shù)量,當線程池的任務(wù)隊列滿了之后,可以創(chuàng)建的最大線程數(shù)。
這是古代大戶人家最多可以雇傭的人數(shù),比如某個節(jié)日或大戶人家有人過壽時,因為活太多,僅靠“長工”是完不成任務(wù),這時就會再招聘一些“短工”一起來干活,這個最大線程數(shù)就是“長工”+“短工”的總?cè)藬?shù),也就是招聘的人數(shù)不能超過 maximumPoolSize。
注意事項
最大線程數(shù) maximumPoolSize 的值不能小于核心線程數(shù) corePoolSize,否則在程序運行時會報 IllegalArgumentException 非法參數(shù)異常,如下圖所示:
參數(shù)3:keepAliveTime
空閑線程存活時間,當線程池中沒有任務(wù)時,會銷毀一些線程,銷毀的線程數(shù)=maximumPoolSize(最大線程數(shù))-corePoolSize(核心線程數(shù))。
還是以大戶人家為例,當大戶人家比較忙的時候就會雇傭一些“短工”來干活,但等干完活之后,不忙了,就會將這些“短工”辭退掉,而 keepAliveTime 就是用來描述沒活之后,短工可以在大戶人家待的(最長)時間。
參數(shù)4:TimeUnit
時間單位:空閑線程存活時間的描述單位,此參數(shù)是配合參數(shù) 3 使用的。參數(shù) 3 是一個 long 類型的值,比如參數(shù) 3 傳遞的是 1,那么這個 1 表示的是 1 天?還是 1 小時?還是 1 秒鐘?是由參數(shù) 4 說了算的。TimeUnit 有以下 7 個值:
- TimeUnit.DAYS:天
- TimeUnit.HOURS:小時
- TimeUnit.MINUTES:分
- TimeUnit.SECONDS:秒
- TimeUnit.MILLISECONDS:毫秒
- TimeUnit.MICROSECONDS:微妙
- TimeUnit.NANOSECONDS:納秒
參數(shù)5:BlockingQueue
阻塞隊列:線程池存放任務(wù)的隊列,用來存儲線程池的所有待執(zhí)行任務(wù)。它可以設(shè)置以下幾個值:
- ArrayBlockingQueue:一個由數(shù)組結(jié)構(gòu)組成的有界阻塞隊列。
- LinkedBlockingQueue:一個由鏈表結(jié)構(gòu)組成的有界阻塞隊列。
- SynchronousQueue:一個不存儲元素的阻塞隊列,即直接提交給線程不保持它們。
- PriorityBlockingQueue:一個支持優(yōu)先級排序的無界阻塞隊列。
- DelayQueue:一個使用優(yōu)先級隊列實現(xiàn)的無界阻塞隊列,只有在延遲期滿時才能從中提取元素。
- LinkedTransferQueue:一個由鏈表結(jié)構(gòu)組成的無界阻塞隊列。與SynchronousQueue類似,還含有非阻塞方法。
- LinkedBlockingDeque:一個由鏈表結(jié)構(gòu)組成的雙向阻塞隊列。
比較常用的是 LinkedBlockingQueue,線程池的排隊策略和 BlockingQueue 息息相關(guān)。
參數(shù)6:ThreadFactory
線程工廠:線程池創(chuàng)建線程時調(diào)用的工廠方法,通過此方法可以設(shè)置線程的優(yōu)先級、線程命名規(guī)則以及線程類型(用戶線程還是守護線程)等。線程工廠的使用示例如下:
public static void main(String[] args) {
// 創(chuàng)建線程工廠
ThreadFactory threadFactory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
// 創(chuàng)建線程池中的線程
Thread thread = new Thread(r);
// 設(shè)置線程名稱
thread.setName("Thread-" + r.hashCode());
// 設(shè)置線程優(yōu)先級(最大值:10)
thread.setPriority(Thread.MAX_PRIORITY);
//......
return thread;
}
};
// 創(chuàng)建線程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 0,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
threadFactory); // 使用自定義的線程工廠
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
Thread thread = Thread.currentThread();
System.out.println(String.format("線程:%s,線程優(yōu)先級:%d",
thread.getName(), thread.getPriority()));
}
});
}
以上程序的執(zhí)行結(jié)果如下:
從上述執(zhí)行結(jié)果可以看出,自定義線程工廠起作用了,線程的名稱和線程的優(yōu)先級都是通過線程工廠設(shè)置的。
參數(shù)7:RejectedExecutionHandler
拒絕策略:當線程池的任務(wù)超出線程池隊列可以存儲的最大值之后,執(zhí)行的策略。默認的拒絕策略有以下 4 種:
- AbortPolicy:拒絕并拋出異常。
- CallerRunsPolicy:使用當前調(diào)用的線程來執(zhí)行此任務(wù)。
- DiscardOldestPolicy:拋棄隊列頭部(最舊)的一個任務(wù),并執(zhí)行當前任務(wù)。
- DiscardPolicy:忽略并拋棄當前任務(wù)。
線程池的默認策略是 AbortPolicy 拒絕并拋出異常。
總結(jié)
本文介紹了線程池的 7 大參數(shù):
- corePoolSize:核心線程數(shù),線程池正常情況下保持的線程數(shù),大戶人家“長工”的數(shù)量。
- maximumPoolSize:最大線程數(shù),當線程池繁忙時最多可以擁有的線程數(shù),大戶人家“長工”+“短工”的總數(shù)量。
- keepAliveTime:空閑線程存活時間,沒有活之后“短工”可以生存的最大時間。
- TimeUnit:時間單位,配合參數(shù) 3 一起使用,用于描述參數(shù) 3 的時間單位。
- BlockingQueue:線程池的任務(wù)隊列,用于保存線程池待執(zhí)行任務(wù)的容器。
- ThreadFactory:線程工廠,用于創(chuàng)建線程池中線程的工廠方法,通過它可以設(shè)置線程的命名規(guī)則、優(yōu)先級和線程類型。
- RejectedExecutionHandler:拒絕策略,當任務(wù)量超過線程池可以保存的最大任務(wù)數(shù)時,執(zhí)行的策略。