ThreadPoolExecutor 用于創(chuàng)建線程池,它有 4 個(gè)重載構(gòu)造器,我們以最多參數(shù)的構(gòu)造器講解:
ThreadPoolExecutor(int corePoolSize, # 線程池核心線程個(gè)數(shù),默認(rèn)線程池線程個(gè)數(shù)為 0,只有接到任務(wù)才新建線程
int maximumPoolSize, # 線程池最大線程數(shù)量
long keepAliveTime, # 線程池空閑時(shí),線程存活的時(shí)間,當(dāng)線程池中的線程數(shù)大于 corePoolSize 時(shí)才會(huì)起作用
TimeUnit unit, # 時(shí)間單位
BlockingQueue<Runnable> workQueue, # 阻塞隊(duì)列,當(dāng)達(dá)到線程數(shù)達(dá)到 corePoolSize 時(shí),將任務(wù)放入隊(duì)列等待線程處理
ThreadFactory threadFactory, # 線程工廠
RejectedExecutionHandler handler) # 線程拒絕策略,當(dāng)隊(duì)列滿了并且線程個(gè)數(shù)達(dá)到 maximumPoolSize 后采取的策略
阻塞隊(duì)列有以下 4 種:
ArrayBlockingQueue:基于數(shù)組、有界,按 FIFO(先進(jìn)先出)原則對(duì)元素進(jìn)行排序;
LinkedBlockingQueue:基于鏈表,按FIFO (先進(jìn)先出) 排序元素,吞吐量通常要高于 ArrayBlockingQueue;
SynchronousQueue:每個(gè)插入操作必須等到另一個(gè)線程調(diào)用移除操作,否則插入操作一直處于阻塞狀態(tài),吞吐量通常要高于 LinkedBlockingQueue;
PriorityBlockingQueue:具有優(yōu)先級(jí)的、無(wú)限阻塞隊(duì)列。
線程拒絕策略有以下 4 種:
CallerRunsPolicy:如果發(fā)現(xiàn)線程池還在運(yùn)行,就直接運(yùn)行這個(gè)線程;
DiscardOldestPolicy:在線程池的等待隊(duì)列中,將頭取出一個(gè)拋棄,然后將當(dāng)前線程放進(jìn)去;
DiscardPolicy:默默丟棄,不拋出異常;
AbortPolicy:java默認(rèn),拋出一個(gè)異常(RejectedExecutionException)。
實(shí)現(xiàn)原則:
如果當(dāng)前池大小 poolSize 小于 corePoolSize ,則創(chuàng)建新線程執(zhí)行任務(wù);
如果當(dāng)前池大小 poolSize 大于 corePoolSize ,且等待隊(duì)列未滿,則進(jìn)入等待隊(duì)列;
如果當(dāng)前池大小 poolSize 大于 corePoolSize 且小于 maximumPoolSize ,且等待隊(duì)列已滿,則創(chuàng)建新線程執(zhí)行任務(wù);
如果當(dāng)前池大小 poolSize 大于 corePoolSize 且大于 maximumPoolSize ,且等待隊(duì)列已滿,則調(diào)用拒絕策略來(lái)處理該任務(wù);
線程池里的每個(gè)線程執(zhí)行完任務(wù)后不會(huì)立刻退出,而是會(huì)去檢查下等待隊(duì)列里是否還有線程任務(wù)需要執(zhí)行,如果在 keepAliveTime 里等不到新的任務(wù)了,那么線程就會(huì)退出。
2.2.3 內(nèi)置線程池
在 java.util.concurrent 包中已經(jīng)提供為大多數(shù)使用場(chǎng)景的內(nèi)置線程池:
Executors.newSingleThreadExecutor() # 單條線程
Executors.newFixedThreadPool(int n) # 固定數(shù)目線程的線程池
Executors.newCachedThreadPool() # 創(chuàng)建一個(gè)可緩存的線程池,調(diào)用execute 將重用以前構(gòu)造的線程(如果線程可用)。如果現(xiàn)有線程沒(méi)有可用的,則創(chuàng)建一個(gè)新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。
Executors.newScheduledThreadPool(int n) # 支持定時(shí)及周期性的任務(wù)執(zhí)行的線程池,多數(shù)情況下可用來(lái)替代 Timer 類。
上述 4 種線程池底層都是通過(guò)創(chuàng)建 ThreadPoolExecutor 獲取線程池。
newSingleThreadExecutor
主要用于串行(順序執(zhí)行)操作場(chǎng)景。newFixedThreadPool
主要用于負(fù)載比較重的場(chǎng)景,為了資源的合理利用,需要限制當(dāng)前線程數(shù)量。newCachedThreadPool
主要用于并發(fā)執(zhí)行大量短期的小任務(wù),或者是負(fù)載較輕的服務(wù)器。newScheduledThreadPool
ScheduledExecutorService 繼承 ThreadPoolExecutor。
2.2.4 提交任務(wù)
獲取 ExecutorService 對(duì)象后,我們需要提交任務(wù)來(lái)讓線程池中的線程執(zhí)行,提交任務(wù)的方法有 2 種:
# void execute():提交不需要返回值的任務(wù)
pool.execute(() -> System.out.println("1L"));
# Future<T> submit(): 提交需要返回值的任務(wù)
Future<Long> future = pool.submit(() -> {
System.out.println("1L");
return 1L;
});
Long result = future.get();