Java執行緒池Executor框架詳解
Java的執行緒既是工作單元,也是執行機制。從JDK 5開始,把工作單元與執行機制分離開來。工作單元包括Runnable和Callable,而執行機制由Executor框架提供。
Executor框架簡介
在HotSpot VM的執行緒模型中,Java執行緒(java.lang.Thread)被一對一對映為本地作業系統執行緒。Java執行緒啟動時會建立一個本地作業系統執行緒;當該Java執行緒終止時,這個作業系統執行緒也會被回收。作業系統會排程所有執行緒並將它們分配給可用的CPU。
在上層,Java多執行緒程式通常把應用分解為若干個任務,然後使用使用者級的排程器(Executor框架)將這些任務對映為固定數量的執行緒;在底層,作業系統核心將這些執行緒對映到硬體處理器上。

任務:包括被執行任務需要實現的介面:Runnable介面或Callable介面。
任務的執行:包括任務執行機制的核心介面Executor,以及繼承自Executor的ExecutorService介面。Executor框架有兩個關鍵類實現了ExecutorService介面(ThreadPoolExecutor和ScheduledThreadPoolExecutor)。
非同步計算的結果:包括介面Future和實現Future介面的FutureTask類。


ThreadPoolExecutor
1、FixedThreadPool:稱為可重用固定執行緒數的執行緒池。下面是FixedThreadPool的原始碼實
現。
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
FixedThreadPool的corePoolSize和maximumPoolSize都被設定為建立FixedThreadPool時指定的引數nThreads。
當執行緒池中的執行緒數大於corePoolSize時,keepAliveTime為多餘的空閒執行緒等待新任務的最長時間,超過這個時間後多餘的執行緒將被終止。這裡把keepAliveTime設定為0L,意味著多餘的空閒執行緒會被立即終止。
FixedThreadPool使用無界佇列LinkedBlockingQueue作為執行緒池的工作佇列(佇列的容量為Integer.MAX_VALUE)。使用無界佇列作為工作佇列會對執行緒池帶來如下影響。
1)當執行緒池中的執行緒數達到corePoolSize後,新任務將在無界佇列中等待,因此執行緒池中的執行緒數不會超過corePoolSize。
2)由於1,使用無界佇列時maximumPoolSize將是一個無效引數。
3)由於1和2,使用無界佇列時keepAliveTime將是一個無效引數。
4)由於使用無界佇列,執行中的FixedThreadPool(未執行方法shutdown()或shutdownNow())不會拒絕任務(不會呼叫RejectedExecutionHandler.rejectedExecution方法)。
2、SingleThreadExecutor:使用單個worker執行緒的Executor。下面是SingleThreadExecutor的原始碼實現。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
3、CachedThreadPool:是一個會根據需要建立新執行緒的執行緒池。下面是建立CachedThread-
Pool的原始碼。
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
CachedThreadPool的corePoolSize被設定為0,即corePool為空;maximumPoolSize被設定為Integer.MAX_VALUE,即maximumPool是無界的。這裡把keepAliveTime設定為60L,意味著CachedThreadPool中的空閒執行緒等待新任務的最長時間為60秒,空閒執行緒超過60秒後將會被終止。
CachedThreadPool使用沒有容量的SynchronousQueue作為執行緒池的工作佇列,但CachedThreadPool的maximumPool是無界的。這意味著,如果主執行緒提交任務的速度高於maximumPool中執行緒處理任務的速度時,CachedThreadPool會不斷建立新執行緒。極端情況下,CachedThreadPool會因為建立過多執行緒而耗盡CPU和記憶體資源。
ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor繼承自ThreadPoolExecutor。它主要用來在給定的延遲之後執行任務,或者定期執行任務。

ScheduledThreadPoolExecutor會把待排程的任務(ScheduledFutureTask)放到一個DelayQueue中。
ScheduledFutureTask主要包含3個成員變數,如下:
long型成員變數time,表示這個任務將要被執行的具體時間。
long型成員變數sequenceNumber,表示這個任務被新增到ScheduledThreadPoolExecutor中
的序號。
long型成員變數period,表示任務執行的間隔週期。
DelayQueue封裝了一個PriorityQueue,這個PriorityQueue會對佇列中的ScheduledFutureTask進行排序。排序時,time小的排在前面(時間早的任務將被先執行)。如果兩個ScheduledFutureTask的time相同,就比較sequenceNumber,sequenceNumber小的排在前面(也就是說,如果兩個任務的執行時間相同,那麼先提交的任務將被先執行)。
FutureTask
Future介面和實現Future介面的FutureTask類,代表非同步計算的結果。FutureTask可以處於下面3種狀態:
1)未啟動。FutureTask.run()方法還沒有被執行之前,FutureTask處於未啟動狀態。當建立一個FutureTask,且沒有執行FutureTask.run()方法之前,這個FutureTask處於未啟動狀態。
2)已啟動。FutureTask.run()方法被執行的過程中,FutureTask處於已啟動狀態。
3)已完成。FutureTask.run()方法執行完後正常結束,或被取消(FutureTask.cancel(…)),或執行FutureTask.run()方法時丟擲異常而異常結束,FutureTask處於已完成狀態。
當FutureTask處於未啟動或已啟動狀態時,執行FutureTask.get()方法將導致呼叫執行緒阻塞;
當FutureTask處於已完成狀態時,執行FutureTask.get()方法將導致呼叫執行緒立即返回結果或丟擲異常。
當FutureTask處於未啟動狀態時,執行FutureTask.cancel()方法將導致此任務永遠不會被執行;當FutureTask處於已啟動狀態時,執行FutureTask.cancel(true)方法將以中斷執行此任務執行緒的方式來試圖停止任務;當FutureTask處於已啟動狀態時,執行FutureTask.cancel(false)方法將不會對正在執行此任務的執行緒產生影響(讓正在執行的任務執行完成);當FutureTask處於已完成狀態時,執行FutureTask.cancel(…)方法將返回false。

FutureTask的實現也是基於AbstractQueuedSynchronizer(AQS)。

Sync是FutureTask的內部私有類,它繼承自AQS。建立FutureTask時會建立內部私有的成員物件Sync,FutureTask所有的的公有方法都直接委託給了內部私有的Sync。