知識總結之 AsyncTask 源碼解析
雖然這個類沒什麼特別地方,也是很常用的類,前段時間面試發現很多公司還是很喜歡問到這個類的原理,及使用場景,so,這裏做下總結。
一、 一句話概括
「AsyncTask = ThreadPool + Handler;」
AsyncTasks是android提供的輕量級執行異步任務的類,提供了執行耗時任務的方法,及各個任務階段UI線程回調。
二、 優缺點
優點
使用簡單,適度封裝
輕量級,有一定可控度
缺點
多個任務同時使用時,默認會用串行化執行器,缺乏線程調度。
任務取消需要自行控制,有一定內存泄漏風險。
三、 類結構
四、 知道點
1,WorkerRunable and FutureTask
每new一個AsyncTask, 會在構造器中新建一個WorkerRunable 和 FutureTask。其中WorkerRunable 實現了Callable藉口,其作用個人理解只是 實際任務執行與調度器FutureTask 的一個溝通橋樑,
而FutureTask作爲每次任務的一次封裝,被放入Execute等代線程池執行。
2,SerialExecutor
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
任務執行器,可以說是Task調度器,決定了每個task是按照什麼規程執行。實現了Executor接口,用ArrayDeque保存了放進了的task。
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
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;
}
從這裏可以看出AsyncTask默認的調度執行器用的這個SerialExecutor,SERIAL_EXECUTOR爲靜態類型,而這個類決定了Task是串行執行,且每個進程共享一個執行器,所以需要自己保證任務執行的優先級及頻率。
THREAD_POOL_EXECUTOR線程池,BlockingQueue初始化大小爲128,說明了線程池中runable個數超過128時,將會阻塞,影響性能及正常使用。
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
3,執行入口跟蹤
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
* <p>This method must be invoked on the UI thread.
*
* @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a
* convenient process-wide thread pool for tasks that are loosely coupled.
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #execute(Object[])
*/
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
上面方法爲執行方法入口,這裏可以自定義執行調度器Executor,實現自己的Task調度規則。
建議適當使用AsyncTask,單純的後臺任務可以用線程池,如果有大量後臺執行調度任務,建議使用JobQueue開源組件,當然可以自己升級JobQueue,
添加JobScheduler支持。
4. BlockingQueue
BlockingQueue很好的解決了多線程中,如何高效安全“傳輸”數據的問題。通過這些高效並且線程安全的隊列類,爲我們快速搭建高質量的多線程程序帶來極大的便利。某些情況下會掛起線程(即阻塞),一旦條件滿足,被掛起的線程又會自動被喚醒
該類爲多線程環境下的生產者與消費者資源的競爭提供了有效的調度共享規則。
方法
- offer,如果可能將對象放入隊列, 返回true。反之false。可加參數 時間 給以一定時間限制。
- put, 如果可能將對象放入隊列,反之將阻塞,直到條件滿足。
- poll, 從隊列拿出一個對象,取不到返回null。可加參數 時間 給以一定時間限制。
- take 取出對象,否則阻塞等待返回對象。
- drainTo 一次性獲取所有對象
子類
- ArrayBlockingQueue, 長數組實現,整形變量控制頭部和尾部。
- LinkedBlockingQueue, 內部緩存隊列由鏈表組成,默認爲無限大。
- DelayQueue,沒有大小限制,so生產者永不會由阻塞,隻手消費者纔會。
- PriorityBlockingQueue, 基於優先級,不會阻塞數據生產者,只會在沒有可消費的數據時,阻塞消費者。
- SynchronousQueue, 無緩衝等待隊列,等於沒有緩存的BlockingQueue,隨時可能阻塞。