官方+白話講解Executors、ThreadPoolExecutor線程池使用
Executors:JDK給提供的線程工具類,靜态方法建構線程池服務ExecutorService,也就是ThreadPoolExecutor,使用預設線程池配置參數。
建議:對于大使用者,高并發,不易掌控的項目,不建議使用Executors來建立線程池對象。
對于易于掌控且并發數不高的項目,可以考慮Executors。
ThreadPoolExecutor:線程池對象,實作ExecutorService接口,可以自定義線程池核心線程數、最大線程數、空閑時間、緩沖隊列等。
建議:大使用者,高并發,不易于掌控的項目,建議根據實體伺服器配置,任務需求耗時,可能存在的并發量,自定義配置ThreadPoolExecutor線程資訊。
一般項目會封裝ThreadPoolExecutor工具類,因為需要考慮新手有時會亂用,也友善于統一靈活管理。
一、先說下Executors 建立線程池的三種政策
1.建立無邊界緩存線程池:Executors.newCachedThreadPool()
無邊界緩存界線程池:不限制最大線程數的線程池,且線程有空閑存活時長。
接着看下JDK Executors.newCachedThreadPool()源碼:
源碼可以可以看到,該方法建立了一個線程池為:核心線程數0,最大線程數Integer.MAX_VALUE(可以了解為無上限),線程空閑存活時長60,機關TimeUnit.SECONDS秒,緩沖隊列是SynchronousQueue的線程池。
因為最大線程數沒有上限,是以,大使用者,高并發項目使用時一定要嚴謹配置。
關于SynchronousQueue緩沖隊列的緩沖數是1,不過每次都被線程池建立取走,是以該緩沖對聯永遠isEmpty=true。具體細節先百度,後續有時間我再講解。
2.建立有邊界線程池:Executors.newFixedThreadPool(200)
有邊界線程池:有最大線程數限制的線程池。
接着看下JDK Executors.newFixedThreadPool(200)源碼:
源碼可以可以看到,該方法建立了一個線程池為:核心線程數nThreads(200),最大線程數nThreads (200),線程空閑存活時長0,機關TimeUnit.SECONDS秒,緩沖隊列是LinkedBlockingQueue的線程池。
LinkedBlockingQueue這裡沒有定義長度,也就是說這個緩沖隊列的容量沒有上限,大使用者,高并發項目使用時一定要嚴謹配置。
3.建立單線程線程池:Executors.newSingleThreadExecutor()
單線程線程池:線程池裡隻有一個線程數,其他都存在緩沖隊列裡,
接着看下JDK Executors.newSingleThreadExecutor()源碼:
源碼可以可以看到,該方法建立了一個線程池為:核心線程數1,最大線程數1,線程空閑存活時長0,機關TimeUnit.MILLISECONDS毫秒,緩沖隊列是LinkedBlockingQueue的線程池。
LinkedBlockingQueue這裡沒有定義長度,也就是說這個緩沖隊列的容量沒有上限,大使用者,高并發項目使用時一定要嚴謹配置。
使用場景:任務需要逐一排程執行。
二、ThreadPoolExecutor自定義配置線程池對象
通過上面的Executors,我們對建立線程池已經有了點了解。
下面直接看構造函數的源碼,我把參數解釋為白話文
/**
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
核心線程數,核心線程數永遠小于等于最大線程數。
緩沖隊列不滿時,線程池的線程數用遠小于等于核心線程數。
緩沖隊列滿時,線程池會在核心線程數的基礎上再建立線程,但小于最大線程數
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
線程池最大線程數
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
線程空閑存活時長
* @param unit the time unit for the {@code keepAliveTime} argument
線程存活時長機關
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
緩沖隊列,BlockingQueue接口的實作類,根據需求選擇他的實作類即可,細節有必要去找度娘。
常用BlockingQueue有LinkedBlockingQueue和SynchronousQueue
* @param threadFactory the factory to use when the executor
* creates a new thread
線程工廠,用來建立線程的,使用預設的就好
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
緩沖隊列已滿且已經最大線程數,這時的處理政策
RejectedExecutionHandler下有多個實作類,根據所需決定
*/
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
在開發實戰中,對于多線程頗為了解的,我建議根據硬體和軟體需求結合,自定義建立ThreadPoolExecutor線程池。