在Android中,UI操作是線程不安全的,如果想要在子線程中進行UI操作,或者在主線程中進行耗時操作,則需要借助Android的異步消息處理機制。但我們需要開啟N個線程的時候,我們可以這樣做:
- 直接new N個Thread。這樣不利于線程管理,而且一般的Thread是沒有返回線程執行完畢的返回值的。
- 通過Handler與主線程通信。
- 異步任務管理類AsyncTask。Android 1.5版本后引入,結合Thread和Handler,非常靈活方便的從子線程切換到UI線程。
AsyncTask之所以如此強大,核心在于背后的線程池。下面我們就一起來了解一下AsyncTask與線程池的那點事。
AsyncTask線程池
AsyncTask中提供兩種線程池,但是其實在AsyncTask中只有一個線程池THREAD_POOL_EXECUTOR,只不過SERIAL_EXECUTOR實現了線程隊列,最終還是使用的THREAD_POOL_EXECUTOR:
- THREAD_POOL_EXECUTOR:多個任務在線程池中異步并發執行
- SERIAL_EXECUTOR:多個線程按串行同步方式執行
THREAD_POOL_EXECUTOR 異步線程池
構造方法:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);
}
其中:
- corePoolSize:線程池的核心運行線程數量
- maximumPoolSize:線程池中可以創建的最大運行線程數量(包括核心運行線程)
- keepAliveTime:當線程池線程數量超過corePoolSize時,多余的空余線程在緩沖隊列的存活時間,超時后將會被移除
- unit:線程池維護線程所允許的空閑時間的單位,一般設置為秒
- workQueue:線程池所使用的緩沖隊列,可以設置緩沖隊列容納的線程數量
- threadFactory:線程工廠,用于創建線程。 當一個異步任務執行execute的時候將會通過該工廠new出一個thread
構造方法分析完畢,那么我們來看看AsyncTask中是什么樣的:
從AsyncTask默認構造的THREAD_POOL_EXECUTOR可以看出,AsyncTask最大支持的緩沖任務隊列是128個。
SERIAL_EXECUTOR 串行線程池
在ActivityThread中的有一段代碼,設置了當Android 版本api 小于12,也就是版本小于3.1時,默認是使用AsyncTask默認的異步線程池THREAD_POOL_EXECUTORAndroid 3.1 之后使用的是 SERIAL_EXECUTOR
執行AsyncTask的兩個方法
- execute:使用的是AsyncTask默認的線程池。在3.1版本之前默認使用THREAD_POOL_EXECUTOR異步并發線程池,且系統默認最大并發執行5個線程,緩沖線程隊列最大128個。3.1版本之后系統,默認是使用SERIAL_EXECUTOR串行任務執行,異步任務將會是一個個順序執行。
- executeOnExecutor 需要傳遞進去一個Executor,可以實現自定義線程池
Executor executor = new ThreadPoolExecutor(10,50,10, TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>(100));
new MyAsyncTask(progressBar).executeOnExecutor(executor);
AsyncTask優點
- 內部采用了線程池機制,可以有效的管理線程
- 可以自定義線程池,實現多個線程按順序同步執行、異步并發執行
- 提供了回調方法,后臺任務執行完畢后會返回需要的數據,拿到數據后可以直接更新UI控件
當然,AsyncTask也是有缺點的,在3.1系統下默認使用AsyncTask線程池,不可以自定義線程池,如果線程不多,即使只有一個異步任務,還是會創建其他4個核心線程,非常耗能。
參考資料
AsyncTask
Android AsyncTask完全解析,帶你從源碼的角度徹底理解
Android AsyncTask(1)-使用方法和線程池解析