標籤:
前言:
上篇主要介紹了使用線程池的好處以及ExecutorService介面,然後學習了通過Executors工廠類產生滿足不同需求的簡單線程池,但是有時候我們需要相對複雜的線程池的時候就需要我們自己來自訂一個線程池,今天來學習一下ThreadPoolExecutor,然後結合使用情境定義一個按照線程優先順序來執行的任務的線程池。
ThreadPoolExecutor
ThreadPoolExecutor線程池用於管理線程任務隊列、若干個線程。
1.)ThreadPoolExecutor建構函式
ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue)ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue workQueue,RejectedExecutionHandler handler)ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler) ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize: 線程池維護線程的最少數量
maximumPoolSize:線程池維護線程的最大數量
keepAliveTime: 線程池維護線程所允許的空閑時間
unit: 線程池維護線程所允許的空閑時間的單位
workQueue: 線程池所使用的緩衝隊列
threadFactory:線程池用於建立線程
handler: 線程池對拒絕任務的處理策略
2.)
建立新線程
預設使用Executors.defaultThreadFactory(),也可以通過如下方式
/** * 建立線程工廠 */ private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); @Override public Thread newThread(Runnable runnable) { return new Thread(runnable, "download#" + mCount.getAndIncrement()); } };
3.)
線程建立規則
ThreadPoolExecutor對象初始化時,不建立任何執行線程,當有新任務進來時,才會建立執行線程。構造ThreadPoolExecutor對象時,需要配置該對象的核心線程池大小和最大線程池大小
1. 當目前執行線程的總數小於核心線程大小時,所有新加入的任務,都在新線程中處理。
2. 當目前執行線程的總數大於或等於核心線程時,所有新加入的任務,都放入任務緩衝隊列中。
3. 當目前執行線程的總數大於或等於核心線程,並且緩衝隊列已滿,同時此時線程總數小於線程池的最大大小,那麼建立新線程,加入線程池中,協助處理新的任務。
4. 當所有線程都在執行,線程池大小已經達到上限,並且緩衝隊列已滿時,就rejectHandler拒絕新的任務。
4.)預設的RejectExecutionHandler拒絕執行策略
1. AbortPolicy 直接丟棄新任務,並拋出RejectedExecutionException通知調用者,任務被丟棄
2. CallerRunsPolicy 用調用者的線程,執行新的任務,如果任務執行是有嚴格次序的,請不要使用此policy
3. DiscardPolicy 靜默丟棄任務,不通知調用者,在處理網路報文時,可以使用此任務,靜默丟棄沒有幾乎處理的報文
4. DiscardOldestPolicy 丟棄最舊的任務,處理網路報文時,可以使用此任務,因為報文處理是有時效的,超過時效的,都必須丟棄
我們也可以寫一些自己的RejectedExecutionHandler,例如拒絕時,直接將線程加入緩衝隊列,並阻塞調用者,或根據任務的時間戳記,丟棄超過限制的任務。
5.)任務隊列BlockingQueue
排隊原則
1. 如果啟動並執行線程少於 corePoolSize,則 Executor 始終首選添加新的線程,而不進行排隊。
2. 如果啟動並執行線程等於或多於 corePoolSize,則 Executor 始終首選將請求排入佇列,而不添加新的線程。
3. 如果無法將請求排入佇列,則建立新的線程,除非建立此線程超出 maximumPoolSize,在這種情況下,任務將被拒絕。
常見幾種BlockingQueue實現
1. ArrayBlockingQueue : 有界的數組隊列
2. LinkedBlockingQueue : 可支援有界/無界的隊列,使用鏈表實現
3. PriorityBlockingQueue : 優先隊列,可以針對任務排序
4. SynchronousQueue : 隊列長度為1的隊列,和Array有點區別就是:client thread提交到block queue會是一個阻塞過程,直到有一個worker thread串連上來poll task。
6.)線程池執行
execute()方法中,調用了三個私人方法
addIfUnderCorePoolSize():線上程池大小小於核心線程池大小的情況下,擴充線程池
addIfUnderMaximumPoolSize():線上程池大小小於線程池大小上限的情況下,擴充線程池
ensureQueuedTaskHandled():保證線上程池關閉的情況下,新排入佇列的線程也能正確處理
7.)線程池關閉
shutdown():不會立即終止線程池,而是要等所有任務緩衝隊列中的任務都執行完後才終止,但再也不會接受新的任務
shutdownNow():立即終止線程池,並嘗試打斷正在執行的任務,並且清空任務緩衝隊列,返回尚未執行的任務
ThreadPoolExecutor實現優先順序線程池 1.)定義線程優先順序枚舉
/** * 線程優先順序 */public enum Priority { HIGH, NORMAL, LOW}
2.)定義線程任務
/** * 帶有優先順序的Runnable類型 *//*package*/ class PriorityRunnable implements Runnable { public final Priority priority;//任務優先順序 private final Runnable runnable;//任務真正執行者 /*package*/ long SEQ;//任務唯一標示 public PriorityRunnable(Priority priority, Runnable runnable) { this.priority = priority == null ? Priority.NORMAL : priority; this.runnable = runnable; } @Override public final void run() { this.runnable.run(); }}
3.)定義一個PriorityExecutor繼承ThreadPoolExecutor
public class PriorityExecutor extends ThreadPoolExecutor { private static final int CORE_POOL_SIZE = 5;//核心線程池大小 private static final int MAXIMUM_POOL_SIZE = 256;//最大線程池隊列大小 private static final int KEEP_ALIVE = 1;//保持存活時間,當線程數大於corePoolSize的空閑線程能保持的最大時間。 private static final AtomicLong SEQ_SEED = new AtomicLong(0);//主要擷取新增工作 /** * 建立線程工廠 */ private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); @Override public Thread newThread(Runnable runnable) { return new Thread(runnable, "download#" + mCount.getAndIncrement()); } }; /** * 線程隊列方式 先進先出 */ private static final Comparator<Runnable> FIFO = new Comparator<Runnable>() { @Override public int compare(Runnable lhs, Runnable rhs) { if (lhs instanceof PriorityRunnable && rhs instanceof PriorityRunnable) { PriorityRunnable lpr = ((PriorityRunnable) lhs); PriorityRunnable rpr = ((PriorityRunnable) rhs); int result = lpr.priority.ordinal() - rpr.priority.ordinal(); return result == 0 ? (int) (lpr.SEQ - rpr.SEQ) : result; } else { return 0; } } }; /** * 線程隊列方式 後進先出 */ private static final Comparator<Runnable> LIFO = new Comparator<Runnable>() { @Override public int compare(Runnable lhs, Runnable rhs) { if (lhs instanceof PriorityRunnable && rhs instanceof PriorityRunnable) { PriorityRunnable lpr = ((PriorityRunnable) lhs); PriorityRunnable rpr = ((PriorityRunnable) rhs); int result = lpr.priority.ordinal() - rpr.priority.ordinal(); return result == 0 ? (int) (rpr.SEQ - lpr.SEQ) : result; } else { return 0; } } }; /** * 預設背景工作執行緒數5 * * @param fifo 優先順序相同時, 等待隊列的是否優先執行先加入的任務. */ public PriorityExecutor(boolean fifo) { this(CORE_POOL_SIZE, fifo); } /** * @param poolSize 背景工作執行緒數 * @param fifo 優先順序相同時, 等待隊列的是否優先執行先加入的任務. */ public PriorityExecutor(int poolSize, boolean fifo) { this(poolSize, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, new PriorityBlockingQueue<Runnable>(MAXIMUM_POOL_SIZE, fifo ? FIFO : LIFO), sThreadFactory); } public PriorityExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); } /** * 判斷當前線程池是否繁忙 * @return */ public boolean isBusy() { return getActiveCount() >= getCorePoolSize(); } /** * 提交任務 * @param runnable */ @Override public void execute(Runnable runnable) { if (runnable instanceof PriorityRunnable) { ((PriorityRunnable) runnable).SEQ = SEQ_SEED.getAndIncrement(); } super.execute(runnable); }}
裡面定義了兩種線程隊列模式: FIFO(先進先出) LIFO(後進先出) 優先順序相同的按照提交先後排序
4.)測試程式
ExecutorService executorService = new PriorityExecutor(5, false); for (int i = 0; i < 20; i++) { PriorityRunnable priorityRunnable = new PriorityRunnable(Priority.NORMAL, new Runnable() { @Override public void run() { Log.e(TAG, Thread.currentThread().getName()+"優先順序正常"); } }); if (i % 3 == 1) { priorityRunnable = new PriorityRunnable(Priority.HIGH, new Runnable() { @Override public void run() { Log.e(TAG, Thread.currentThread().getName()+"優先順序高"); } }); } else if (i % 5 == 0) { priorityRunnable = new PriorityRunnable(Priority.LOW, new Runnable() { @Override public void run() { Log.e(TAG, Thread.currentThread().getName()+"優先順序低"); } }); } executorService.execute(priorityRunnable); }
運行結果:不難發現優先順序高基本上優先執行了 最後執行的基本上優先順序比較低
Android線程管理之ThreadPoolExecutor自訂線程池(三)