使用線程池的好處:
- 重用線程池中的線程,避免因線程的創建和銷燬所帶來的性能開銷.
- 有效控制線程池的最大併發數,避免大量的線程之間因相互爭搶系統資源而造成堵塞現象.
- 對線程進行簡單管理,並提供定時執行以及指定間隔循環執行等功能.
Android中的線程池的概念來源於Java中的Executer(接口),實現爲ThreadPoolExecutor.提供一系列參數來配置線程池,通過不同的參數創建不同的線程池.
Android中的線程池主要分爲4類,可以通過Executer的工廠方法得到.由於Android中的線程池都是直接或者間接通過配置ThreadPoolExecutor來實現,所以首先我們先介紹一下ThreadPoolExecutor.
ThreadPoolExecutor的參數
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
corePoolSize
線程池的核心線程數.默認情況下,核心線程會在線程池中一直存活,即便它們處於閒置狀態.但如果將ThreadPoolExecutor的allowCoreThreadTimeOut屬性設置爲true,那麼閒置的核心線程在等待任務到來時會有超時機制,這個時間間隔由keepAliveTime 指定.當等待時間超過指定時長,核心線程也會被終止.
maximumPoolSize
線程池所能容納的最大線程數,當活動線程數達到這個數值後,後續的新任務將會被阻塞.
keepAliveTime
非核心線程閒置時的超時時長,超過時長,非核心線程會被回收.當ThreadPoolExecutor的allowCoreThreadTimeOut屬性設置爲true時,keepAliveTime也會做用於核心線程.
unit
用於指定keepAliveTime參數的時間單位,是一個枚舉,常用的有TimeUnit.MILLISECONDS(毫秒),TimeUnit.SECONDS(秒)以及TimeUnit.MINUTES(分鐘)等.
workQueue
線程池中的任務隊列,通過線程池的execute方法提交的Runnable對象會存儲在這個參數中.
threadFactory
線程工廠,爲線程池提供創建新線程的功能.是一個接口,只有一個方法Thread new Thread(Ruunable runnable).
RejectedExecutionHandler
飽和策略,當隊列和線程池都滿了,說明線程池處於飽和狀態,那麼必須採取一種策略處理提交的新任務,默認值是AbortPolicy,表示無法處理新任務時拋出異常.會拋出RejectedExecutionException來通知調用者.
ThreadPoolExecutor爲RejectedExecutionHandler提供了介個可選值:
- CallerRunPolicy : 只用調用者所在的線程來執行任務.
- DiscardPolicy : 不處理,丟棄掉.
- DiscardOldestPolicy : 丟棄隊列裏最近的一個任務並執行當前任務
ThreadPoolExecutor執行任務時的規則:
- 有新任務時,如果線程池中的線程數量未達到核心線程的數量,直接啓動一個核心線程.
- 如果線程中的線程數量已經達到或者超過核心線程數量,那麼任務會被插入任務隊列排隊等待執行.
- 如果無法將任務插入任務隊列時,往往可能是由於任務隊列已滿,這時如果線程數量未到達線程池規定的最大值,那麼會立刻啓動一個非核心線程來執行任務.如果線程數量已經達到線程池規定的最大值,那麼就拒絕執行該任務,同時ThreadPoolExecutor會調用RejectedExecutionHandler的rejectedExecution方法來通知調用者.
ThreadPoolExecutor的配置
AsynTask中也使用了線程池.我們來看一看是如何對線程池進行配置的.
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
分析:
核心線程數:最多4個最少2個;
線程池最大線程數:CPU核心數的2倍+1;
核心線程設置超時機制爲true,超時時間與非核心線程在閒置時的超時時間都爲30秒;
任務隊列的容量:128;
線程池的分類
將常見的線程池根據不同的功能特性分如下幾類:
- FixedThreadPool
- CachedThreadPool
- ScheduledThreadPool
- SingleThreadExecutor
FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
通過Executor.newFixedThreadPool方法創建.
是一種線程數量固定的線程池,當線程處於空閒狀態時,也不會被回收,除非線程池關閉.當所有線程都處於活動狀態時,新任務都會處於等待狀態,直到線程空閒出來.由於FixThreadPool只有核心線程並且不會被回收,所以它能夠更快的響應外界的請求.
CachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
通過Executor.newCachedThreadPool方法創建.是一種線程數量不定的線程池,並且最大線程數爲Integer.MAX_VALUE(0x7fffffff),所以實際上最大線程數可以任意大.當線程池中的線程都處於活動狀態時,線程池會創建新的線程來處理新任務,否則就會利用空閒的線程來處理新任務.線程池中的空閒線程都有超時機制,這個超時時長爲60秒,超過60秒閒置線程就會被回收.和FixThreadPool不同的是,CachedThreadPool的任務隊列其實相當於一個空集合,這樣任何的任務都會立即被執行,因爲在這種場景下SynchronousQueue是無法插入任務的,SynchronousQueue是一個非常特殊的隊列,在很多情況下可以把它簡單理解爲一個無法存儲元素的隊列.
從CachedThreadPool的特性來看,這類線程池比較審覈執行大量的耗時較少的任務,當整個線程池都處於閒置狀態時,線程池中的線程都會超時而被停止,此時相當於沒有任何線程,幾乎不佔用任何系統資源.
ScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
通過Executor.newSingleThreadExecutor方法創建.它的核心線程數量是固定的,非核心線程數是沒有限制的,並且當非核心線程閒置時會被立即回收.主要用於執行定時任務和具有固定週期的重複任務.
SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
通過Executor.newSingleThreadExecutor方法創建.這類線程池內部只有一個核心線程,它確保所有的任務都在同一個線程中按順序執行.SingleThreadExecutor