為了避免重複的建立執行緒,執行緒池的出現可以讓執行緒進行復用。通俗來講,當有任務提交時,就會向執行緒池拿一個執行緒,當任務完成後,並不是直接關閉執行緒,而是將這個執行緒歸還給執行緒池供其他任務使用。
ThreadPoolExecutor:
ThreadPoolExecutor是執行緒池的實現類。
ThreadPoolExecutor的構造器:
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;
}複製程式碼
構造器引數解析:
corePoolSize:執行緒池的核心池大小,在建立執行緒池之後,執行緒池預設沒有任何執行緒。除非呼叫了prestartAllCoreThreads()或prestartCoreThread()方法,這兩個方法是預建立執行緒的方法,即在沒有任務到來之前會建立corePoolSize個執行緒或者一個執行緒。預設情況下,在建立了執行緒池後,執行緒池中的執行緒數為0,當有任務提交,就會建立一個執行緒去執行任務,當執行緒池的執行緒數目達到corePoolSize後,就會把到達的任務放到快取佇列中。
maximumPoolSize:執行緒池的最大執行緒數。如果阻塞佇列滿了,並且已建立的執行緒數小於最大執行緒數,則執行緒池會在建立新的執行緒執行。
keepAliveTime:表示執行緒沒有任務執行時最多保持多久時間會終止。預設情況下,當執行緒池中的執行緒數大於corePoolSize時,如果一個執行緒空閒時間達到keepAliveTime,執行緒則會終止,直到執行緒池中的執行緒數不大於corePoolSize。如果呼叫了allowCoreThreadTimeOut(boolean)方法,線上程池中的執行緒數不大於corePoolSize時,keepAliveTime引數也會起作用,直到執行緒池中的執行緒數為0。
unit:引數keepAliveTime的時間單位。
workQueue:阻塞佇列,用來儲存等待執行的任務。阻塞佇列一般有以下幾種:
ArrayBlockingQueue;//陣列結構的有界阻塞佇列,先進先出,建立時必須指定大小
LinkedBlockingQueue;//連結串列結構的無界阻塞佇列,先進先出
SynchronousQueue;//不儲存元素的阻塞佇列,每次插入操作必須等到另一個執行緒呼叫移除操作複製程式碼
threadFactory:執行緒工廠,主要用來建立執行緒
handler:拒絕處理任務策略,有以下四種取值。
ThreadPoolExecutor.AbortFactory;//丟棄任務並丟擲RejectedExecutionException異常
ThreadPoolExecutor.DiscardPolicy;//丟棄任務,但不丟擲異常
ThreadPoolExecutor.DiscardOldestPolicy;//丟棄佇列最前面的任務,然後重新嘗試執行任務(重複此過程)
ThreadPoolExecutor.CallerRunsPolicy;//由呼叫執行緒處理該任務複製程式碼
執行緒池的任務處理策略
首先取得當前執行緒池中的執行緒總數,與核心池大小比較,
- 如果小於核心池大小,將通過addWorker()方法建立執行緒執行
- 如果大於,則提交到阻塞佇列
- 如果阻塞佇列已滿,則把任務直接提交到執行緒池
- 如果當前執行緒數達到最大執行緒數,則提交失敗,執行拒絕策略,否則分配執行緒執行。
執行緒池的關閉
ThreadPoolExecutor提供了兩個方法關閉執行緒池:
shutdown();//不會立即終止執行緒池,等所有的任務和阻塞佇列的任務都執行完才終止,但不再接受新的任務。
shutdownNow();//立即終止執行緒池,並嘗試打斷正在執行的任務,並清空阻塞佇列,返回尚未執行的任務複製程式碼
執行緒池的狀態
volatile int runState;
static final int RUNNING = 0;//執行狀態
static final int SHUTDOWN = 1;//關閉狀態
static final int STOP = 2;//停止
static final int TERMINATED = 3;//終止複製程式碼
- 建立執行緒池後,初始狀態為RUNNING
- 如果呼叫了shutdown(),則執行緒池處於SHUTDOWN狀態,此時執行緒池不再接受新的任務,它會等所有任務執行完畢,最後終止。
- 如果呼叫了shutdownNow(),執行緒池處於STOP狀態,此時執行緒池不能接受新的任務,並且去嘗試終止正在執行的任務,返回沒有執行的任務列表。
- 當執行緒池處於SHUTDOWN或STOP狀態,並且所以工作執行緒已經銷燬,阻塞佇列已經清空或執行完之後,執行緒池被設定為TERMINATED狀態。
常見的四種執行緒池
FixedThreadPool:固定大小的執行緒池
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}複製程式碼
固定大小的執行緒池,該執行緒池corePoolSize和maximumPoolSize相等,阻塞佇列為LinkedBlockingQueue。固定大小的執行緒池,不存線上程數量的變化。
SingleThreadExecutor:單執行緒執行緒池
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}複製程式碼
單執行緒執行緒池,只有一個執行緒的執行緒池,阻塞佇列用LinkedBlockingQueue,若有多餘的任務提交到執行緒池中,則會被暫存到阻塞佇列,等空閒時再去執行,按照先進先出的順序執行。該執行緒池可保證任務按照被加入順序執行。
CachedThreadPool:快取執行緒池
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}複製程式碼
快取執行緒池,快取的執行緒預設存活60秒。執行緒池的corePoolSize大小為0,最大執行緒數為Integer.MAX_VALUE,阻塞佇列使用的是SynchronousQueue,是一個直接提交的阻塞佇列,它總會迫使執行緒池增加新的執行緒去執行任務。當執行緒的空間時間超過60s,則工作執行緒將會終止被回收。當提交新任務時,如果沒有空閒執行緒,則建立新執行緒執行任務。
ScheduledThreadPool:定時執行緒池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}複製程式碼
定時執行緒池,可用於週期性地執行任務,通常用於週期性的同步資料。