ThreadPoolExecutor是Executor接口的一個重要的實現類,是線程池的具體實現,用來執行被提交的任務。
一、ThreadPoolExecutor的創建:
- 直接創建ThreadPoolExecutor的實例對象,這樣需要自己配置ThreadPoolExecutor中的每一個參數:
ThreadPoolExecutor tpe = new ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue);
每個參數的具體設置參見:點擊打開鏈接- ThreadPoolExecutor通過Executors工具類來創建ThreadPoolExecutor的子類FixedThreadPool、SingleThreadExecutor、CachedThreadPool,這些子類繼承ThreadPoolExecutor,並且其中的一些參數已經被配置好。
//FixedThreadPoll
ExecutorService ftp = Executors.newFixedThreadPool(int threadNums);
ExecutorService ftp = Executors.newFixedThreadPool(int threadNums, ThreadFactory threadFactory);
//SingleThreadExecutor
ExecutorService ste = Executors.newSingleThreadExecutor();
ExecutorService ste = Executors.newSingleThradPool(ThreadFactory threadFactory);
//CachedThreadPool
ExecutorService ctp = Executors.newCachedThreadPool();
ExecutorService ctp = Executors.newCachedThreadPool(ThreadFactory threadFactory);
關於ThreadFactory接口,參見:點擊打開鏈接
二、ThreadPoolExecutor的子類FixedThreadPool、SingleThreadExecutor、CachedThreadPool詳解
FixedThreadPool、SingleThreadExecutor、CachedThreadPool都是通過Executors工廠類中的工廠方法創建的,因此我們對這幾個方法進行分析。
1、FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
應用場景:FixedThreadPool是線程數量固定的線程池,適用於爲了滿足資源管理的需求,而需要適當限制當前線程數量的情景,適用於負載比較重的服務器。
可以看出它的實現就是把線程池最大線程數量maxmumPoolSize和核心線程池的數量corePoolSize設置爲相等,並且使用LinkedBlockingQueue作爲阻塞隊列,那麼首先可以知道線程池的線程數量最多就是nThread,只會在核心線程池階段創建,此外,因爲LinkedBlockingQueue是無限的雙向隊列,因此當任務不能立刻執行時,都會添加到阻塞隊列中,因此可以得到FixedThreadPool的工作流程大致如下:
- 當前核心線程池總線程數量小於corePoolSize,那麼創建線程並執行任務;
- 如果當前線程數量等於corePoolSize,那麼把 任務添加到阻塞隊列中;
- 如果線程池中的線程執行完任務,那麼獲取阻塞隊列中的任務並執行;
*注意:因爲阻塞隊列是無限的雙向隊列,因此如果沒有調用shutDownNow()或者shutDown()方法,線程池是不會拒絕任務的,如果線程池中的線程一直被佔有,FixedThreadPool是不會拒絕任務的。
因爲使用的是LinkedBlockingQueue,因此maximumPoolSize,keepAliveTime都是無效的,因爲阻塞隊列是無限的,因此線程數量肯定小於等於corePoolSize,因此keepAliveTime是無效的;
2、SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
應用場景:SingleThreadExecutor是隻有一個線程的線程池,常用於需要讓線程順序執行,並且在任意時間,只能有一個任務被執行,而不能有多個線程同時執行的場景。
因爲阻塞隊列使用的是LinkedBlockingQueue,因此和FixedThreadPool一樣,maximumPoolSize,keepAliveTime都是無效的。corePoolSize爲1,因此最多隻能創建一個線程,SingleThreadPool的工作流程大概如下:
- 當前核心線程池總線程數量小於corePoolSize(1),那麼創建線程並執行任務;
- 如果當前線程數量等於corePoolSize,那麼把 任務添加到阻塞隊列中;
- 如果線程池中的線程執行完任務,那麼獲取阻塞隊列中的任務並執行;
3、CachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
應用場景:CachedThreadPool適用於執行很多短期異步任務的小程序,或者是負載較輕的服務器。
CachedThreadPool使用SynchronizedQueue作爲阻塞隊列,SynchronizedQueue是不存儲元素的阻塞隊列,實現“一對一的交付”,也就是說,每次向隊列中put一個任務必須等有線程來take這個任務,否則就會一直阻塞該任務,如果一個線程要take一個任務就要一直阻塞知道有任務被put進阻塞隊列。
因爲CachedThreadPool的maximumPoolSize爲Integer.MUX_VALUE,因此CachedThreadPool是無界的線程池,也就是說可以一直不斷的創建線程。corePoolSize爲0 ,因此在CachedThreadPool中直接通過阻塞隊列來進行任務的提交。
CachedThreadPool的工作流程大概如下:
- 首先執行SynchronizedQueue.offer( )把任務提交給阻塞隊列,如果這時候正好在線程池中有空閒的線程執行SynchronizedQueue.poll( ),那麼offer操作和poll操作配對,線程執行任務;
- 如果執行SynchronizedQueue.offer( )把任務提交給阻塞隊列時maximumPoolSize=0.或者沒有空閒線程來執行SynchronizedQueue.poll( ),那麼步驟1失敗,那麼創建一個新線程來執行任務;
- 如果當前線程執行完任務則循環從阻塞隊列中獲取任務,如果當前隊列中沒有提交(offer)任務,那麼線程等待keepAliveTime時間,在CacheThreadPool中爲60秒,在keepAliveTime時間內如果有任務提交則獲取並執行任務,如果沒有則銷燬線程,因此最後如果一直沒有任務提交了,線程池中的線程數量最終爲0。