概念說明
Executor是用來執行提交的Runnable任務的對象,並以接口的形式定義,提供一種提交任務(submission task)與執行任務(run task)之間的解耦方式,還包含有線程使用與週期調度的詳細細節等。
ExecutorService接口擴展了Executor,提供管理線程池終止的一組方法,還提供了產生Future的方法,Future是用於追蹤一個或多個異步任務的對象,並能返回異步任務的計算結果。一、ThreadPoolExecutor
簡介:ThreadExecutorPool是使用最多的線程池組件,瞭解它的原始資料最好是從從設計者(Doug Lea)的口中知道它的來龍去脈。在Jdk1.6中,ThreadPoolExecutor直接繼承了AbstractExecutorService, 並層級實現了ExecutorService和Executor接口。
線程池處理了兩個問題:1.改善了性能。當執行大量的異步任務時,減少了每次調用的開銷。2.提供了一直資源管理的方式。線程池內部的線程可以得到有效的複用。每個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;
}
參數說明:
1.當線程池小於corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閒線程。
2.當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行
3.當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會創建新線程執行任務
4.當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理
5.當線程池中超過corePoolSize線程,空閒時間達到keepAliveTime時,關閉空閒線程
6.當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閒時間達到keepAliveTime也將關閉
阻塞隊列
ArrayBlockingQueue :一個由數組結構組成的有界阻塞隊列。
LinkedBlockingQueue :一個由鏈表結構組成的有界阻塞隊列。
PriorityBlockingQueue :一個支持優先級排序的無界阻塞隊列。
DelayQueue: 一個使用優先級隊列實現的無界阻塞隊列。
SynchronousQueue: 一個不存儲元素的阻塞隊列。
LinkedTransferQueue: 一個由鏈表結構組成的無界阻塞隊列。
LinkedBlockingDeque: 一個由鏈表結構組成的雙向阻塞隊列。
明確拒絕策略
ThreadPoolExecutor.AbortPolicy: 丟棄任務並拋出RejectedExecutionException異常。 (默認)ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然後重新嘗試執行任務(重複此過程)
ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務
說明:Executors 各個方法的弊端:
1)newFixedThreadPool 和 newSingleThreadExecutor:
主要問題是堆積的請求處理隊列可能會耗費非常大的內存,甚至 OOM。
2)newCachedThreadPool 和 newScheduledThreadPool:
主要問題是線程數最大數是 Integer.MAX_VALUE,可能會創建數量非常多的線程,甚至 OOM。
二、Executors工具類
最近阿里發佈的 Java開發手冊中強制線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。主要是這個工具類提供的工廠方法,使用的都是默認參數,雖然可以通過一些手段進行修改,但是對於新手來說,還是存在風險。
Executors利用工廠模式向我們提供了4種線程池實現方式:
// 創建固定大小的線程池。每次提交一個任務就創建一個線程,直到線程達到線程池的最大大小。
// 線程池的大小一旦達到最大值就會保持不變,如果某個線程因爲執行異常而結束,那麼線程池會補充一個新線程。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
//創建一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當於單線程串行執行所有任務。
//如果這個唯一的線程因爲異常結束,那麼會有一個新的線程來替代它。
//此線程池保證所有任務的執行順序按照任務的提交順序執行。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
// 創建一個可緩存的線程池。如果線程池的大小超過了處理任務所需要的線程,
// 那麼就會回收部分空閒(60秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。
// 此線程池不會對線程池大小做限制,線程池大小完全依賴於操作系統(或者說JVM)能夠創建的最大線程大小。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
//創建一個線程池,它會維持corePoolSize數目個線程,就算線程空閒,也不會被移除。可以週期地或者延時執行任務
//可以用來做定時任務,心跳檢測等功能
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
三、線程調度原理