AsyncTask源碼分析

前言

AsyncTask在Android編程中是一種常用的異步編程方式,那麼AsyncTask到底是什麼呢?下面我們從
基本使用到源碼分析對AsyncTask作一個全面的瞭解。

一般使用

通常我們對AsyncTask的使用是

//1.實現抽象類AsyncTask
Class MyAsyncTask extends AsyncTask{

  @Override  
  protected Object doInBackground(Object[] params) {  
       return null;  
  }  
}
//2.創建實例對象
MyAsyncTask myAsyncTask = New MyAsyncTask();
//3.調用execute方法執行任務
myAsyncTask.execute();

一般使用比較簡單,通過實現AsyncTask抽象類,然後創建一個這樣的子類實例,然後調用execute方法就可以在doInBackground進行異步處理了。

源碼分析

我們看看execute方法的具體實現(這裏針對Android-23源碼分析的,不同版本的源碼實現的方式可能不同,這裏不一一分類了)

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
  return executeOnExecutor(sDefaultExecutor, params);
}

一句代碼,我們看看executeOnExecutor方法的具體實現

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;
    }

首先檢測mState的狀態,如果同一個AsyncTask實例在沒有pending的情況下,再進行execute,那麼會報出相應的異常;然後去設置mState的狀態,調用onPreExecute,去執行exec.execute(mFuture),最終的執行在這裏。那麼我們看看剛纔傳進來的sDefaultExecutor參數。

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

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);
            }
        }
}

實質上是調用SerialExecutor 類的execute方法,首先向mTasks 提交offer隊列的末尾,然後從mTasks 的頭部poll出要執行的runnable.

從名字就可以看出,默認情況下,多個task是加到mTask後執行的。也就是串行執行的。如果要並行執行的畫,通過executeOnExecutor(Async.THREAD_POOL_EXECUTOR,params);
關於doInBackground、onPreExecute、onPostExecute、onProgressUpdate等幾個抽象方法的調線程和時期關係,不想做太多分析,都是模版設計模式思想,在不同地方調用罷了。比較簡單。這裏主要將線程池,這裏纔是AsyncTask的精華所在,以及以後在Android系統使用單獨的線程池時候有個很好的參照。

線程池參數解釋

 private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
 private static final int KEEP_ALIVE = 1;

 private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);
 public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

corePoolSize: 核心線程數目,即使線程池沒有任務,核心線程也不會終止(除非設置了allowCoreThreadTimeOut參數)可以理解爲“常駐線程”

maximumPoolSize: 線程池中允許的最大線程數目;一般來說,線程越多,線程調度開銷越大;因此一般都有這個限制。

keepAliveTime: 當線程池中的線程數目比核心線程多的時候,如果超過這個keepAliveTime的時間,多餘的線程會被回收;這些與核心線程相對的線程通常被稱爲緩存線程

unit: keepAliveTime的時間單位

workQueue: 任務執行前保存任務的隊列;這個隊列僅保存由execute提交的Runnable任務

threadFactory: 用來構造線程池的工廠;一般都是使用默認的;

handler: 當線程池由於線程數目和隊列限制而導致後續任務阻塞的時候,線程池的處理方式。

線程池核心調度思想

那麼,當一個新的任務到達的時候,線程池中的線程是如何調度的呢?

  • 如果線程池中線程的數目少於corePoolSize,就算線程池中有其他的沒事做的核心線程,線程池還是會重新創建一個核心線程;直到核心線程數目到達corePoolSize(常駐線程就位)
  • 如果線程池中線程的數目大於或者等於corePoolSize,但是工作隊列workQueue沒有滿,那麼新的任務會放在隊列workQueue中,按照FIFO的原則依次等待執行;(當有核心線程處理完任務空閒出來後,會檢查這個工作隊列然後取出任務默默執行去)
  • 如果線程池中線程數目大於等於corePoolSize,並且工作隊列workQueue滿了,但是總線程數目小於maximumPoolSize,那麼直接創建一個線程處理被添加的任務。
  • 如果工作隊列滿了,並且線程池中線程的數目到達了最大數目maximumPoolSize,那麼就會用最後一個構造參數handler處理;默認的處理方式是直接丟掉任務,然後拋出一個異常。

具體的實現場景描述:當有新的任務要處理時,先看線程池中的線程數量是否大於 corePoolSize,再看緩衝隊列 workQueue 是否滿,最後看線程池中的線程數量是否大於 maximumPoolSize。另外,當線程池中的線程數量大於 corePoolSize 時,如果裏面有線程的空閒時間超過了 keepAliveTime,就將其移除線程池,這樣,可以動態地調整線程池中線程的數量。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章