AsyncTask源碼分析

Android 線程簡單分析(一) Android 併發之synchronized鎖住的是代碼仍是對象(二) Android 併發之CountDownLatch、CyclicBarrier的簡單應用(三) Android 併發HashMap和ConcurrentHashMap的簡單應用(四)(待發布) Android 併發之Lock、ReadWriteLock和Condition的簡單應用(五) Android 併發之CAS(原子操做)簡單介紹(六) Android 併發Kotlin協程的重要性(七)(待發布) Android 併發之AsyncTask原理分析(八) Android 併發之Handler、Looper、MessageQueue和ThreadLocal消息機制原理分析(九) Android 併發之HandlerThread和IntentService原理分析(十)android

相信AsyncTask你們都不陌生。AsyncTask內部封裝了線程池和Handler,AsyncTask容許咱們在後臺進行耗時操做且把結果及時更新到UI上。固然AsyncTask從最開始到如今已經通過了幾回代碼修改,任務的執行邏輯慢慢地發生了改變,並非你們所想象的那樣:AsyncTask是徹底並行執行的就像多個線程同樣,其實不是的,因此用AsyncTask的時候仍是要注意,下面會一一說明。併發

####AsyncTask究竟是串行仍是並行?async

new MyAsyncTask("MyAsyncTask1").execute("");
new MyAsyncTask("MyAsyncTask2").execute("");
new MyAsyncTask("MyAsyncTask3").execute("");
new MyAsyncTask("MyAsyncTask4").execute("");
new MyAsyncTask("MyAsyncTask5").execute("");
複製代碼

看一下日誌:ide

MyAsyncTask1 === 2019-05-03 07:35:23
MyAsyncTask2 === 2019-05-03 07:35:26
MyAsyncTask3 === 2019-05-03 07:35:29
MyAsyncTask4 === 2019-05-03 07:35:32
MyAsyncTask5 === 2019-05-03 07:35:35
MyAsyncTask6 === 2019-05-03 07:35:38
複製代碼

從5個AsyncTask共耗時15s且時間間隔爲3s,很顯然是串行執行的。高併發

既然下來咱們來分析一下源碼:oop

public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";
    // 獲取當前CPU數量
    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;
    //ThreadFactory 線程工廠,經過工廠方法newThread來獲取新線程
    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());
    }
};
    //阻塞式隊列,用來存放待併發執行的任務,初始容量:128個
    private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128);
    /**
     * 併發線程池,能夠用來並行執行任務,從3.0開始AsyncTask默認是串行執行任務
     * 可是咱們仍然能構造出並行的AsyncTask
     */
    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;
}

    /**
     * 串行任務執行器,其內部實現了串行控制,
     * 循環的取出一個個任務交給上述的併發線程池去執行
     */
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    //消息類型:發送結果
    private static final int MESSAGE_POST_RESULT = 0x1;
    //消息類型:更新進度
    private static final int MESSAGE_POST_PROGRESS = 0x2;
    /**
     * 靜態Handler,用來發送上述兩種通知,採用UI線程的Looper來處理消息,
     * 在Android 5.2以前,AsyncTask必須在UI線程調用,由於子線程
     * 默認沒有Looper沒法建立下面的Handler,程序會直接Crash,可是在5.2以後InternalHandler內部經過
     * sHandler = new InternalHandler(Looper.getMainLooper()),因此不必在UI線程也是能夠的
     */
    private static InternalHandler sHandler;
    private final Handler mHandler;

    /**
     * 默認任務執行器,被賦值爲串行任務執行器,AsyncTask變成串行執行任務,SERIAL_EXECUTOR其內部經過
     * try {r.run();} finally {scheduleNext();}實現了串行執行。
     */
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    // 這兩個就是任務執行體
    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;
    //任務的狀態 默認爲等待狀態,即等待執行,其類型標識爲volatile線程可見
    private volatile Status mStatus = Status.PENDING;
    //原子布爾型,支持高併發訪問,標識任務是否被取消
    private final AtomicBoolean mCancelled = new AtomicBoolean();
    //原子布爾型,支持高併發訪問,標識任務是否被執行過
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
    /**
     * 串行執行器的實現,咱們要好好看看,它是怎麼把並行轉爲串行的
     * 目前咱們須要知道,asyncTask.execute(Params ...)實際上會調用
     * SerialExecutor的execute方法,這一點後面再說明。也就是說:當你的asyncTask執行的時候,
     * 首先你的task會被加入到任務隊列,而後排隊,一個個執行。
     * 總結:
     * <p>
     * 當任務來臨時,首先就是入隊列,而後判斷當前有沒有任務正在執行
     * 若是沒有任務執行則直接調用scheduleNext(),執行任務。
     * 噹噹前任務執行完成又再次在finally塊調用scheduleNext執行下一個任務
     */
    private static class SerialExecutor implements Executor {
        //線性雙向隊列,用來存儲全部的AsyncTask任務
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        //當前正在執行的AsyncTask任務
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            //將新的AsyncTask任務加入到雙向隊列中
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();//執行AsyncTask任務
                    } finally {
                        /**
                         * 當前AsyncTask任務執行完畢後,進行下一輪執行,若是還有未執行任務的話
                         * 這一點很明顯體現了AsyncTask是串行執行任務的,老是一個任務執行完畢纔會執行下一個任務
                         */
                        scheduleNext();
                    }
                }
            });

            //若是當前沒有任務在執行,直接進入執行邏輯
            if (mActive == null) {
                scheduleNext();
            }
        }

        //從任務隊列中取出隊列頭部的任務,若是有就交給併發線程池去執行
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

    public enum Status {
        /**
         * 任務等待執行
         */
        PENDING,
        /**
         * 任務正在執行
         */
        RUNNING,
        /**
         * 任務已經執行結束
         */
        FINISHED,
    }
    /**
     * 在Android 5.2以前,AsyncTask必須在UI線程調用,由於子線程
     * 默認沒有Looper沒法建立下面的Handler,程序會直接Crash,可是在5.2以後InternalHandler內部經過
     * sHandler = new InternalHandler(Looper.getMainLooper()),因此不必在UI線程也是能夠的
     */
    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }
    private Handler getHandler() {
        return mHandler;
    }
    /**
     * @hide 設置默認執行器
     */
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }
    /**
     * 建立新的任務,這個方法必須在UI線程中調用,其實在5.2以後工做線程也是能夠的
     */
    public AsyncTask() { this((Looper) null); }
    /**
     * 建立新的任務,這個方法必須在UI線程中調用,其實在5.2以後工做線程也是能夠的
     *
     * @hide
     */
    public AsyncTask(@Nullable Handler handler) { this(handler != null ? handler.getLooper() : null); }
    /**
     * 建立新的任務,這個方法必須在UI線程中調用,其實在5.2以後工做線程也是能夠的
     *
     * @hide
     */
    public AsyncTask(@Nullable Looper callbackLooper) {
        /**構造Handler*/
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper);
        /**構造任務執行體*/
        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;
            }
    };
        /**構造任務執行體,傳入mWorker*/
        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    //執行Future,經過get獲取結果
                    Result result = get();
                    postResultIfNotInvoked(result);
                } 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);
                }  
            }
        };
    }
    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }
    //doInBackground執行完畢,發送消息
    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
          message.sendToTarget();
        return result;
}
    public final Status getStatus() { return mStatus; }
    /**
     * 這個方法是咱們必需要重寫的,用來作後臺計算,使用指定參數經過execute方法執行任務。
     * 這個方法可以調用publishProgress方法去更新進度。
     * 所在線程:後臺線程
     */
    @WorkerThread
    protected abstract Result doInBackground(Params... params);

    /**
     * 在doInBackground以前調用,用來作初始化工做
     * 所在線程:UI線程
     */
    @MainThread
    protected void onPreExecute() { }
    /**
     * 在doInBackground以後調用,用來接受後臺計算結果更新UI
     * 所在線程:UI線程
     */
    @SuppressWarnings({"UnusedDeclaration"})
    @MainThread
    protected void onPostExecute(Result result) { }
    /**
       * 在publishProgress以後調用,用來更新計算進度
     * 所在線程:UI線程
     */
    @MainThread
    protected void onProgressUpdate(Progress... values) { }
    @MainThread
    protected void onCancelled(Result result) { onCancelled(); }
    /**
     * cancel被調用而且doInBackground執行結束,會調用onCancelled,表示任務被取消
     * 這個時候onPostExecute不會再被調用,兩者是互斥的,分別表示任務取消和任務執行完成
     * 所在線程:UI線程
     */
    @MainThread
    protected void onCancelled() { }
    public final boolean isCancelled() {
        return mCancelled.get();
    }
    public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }
    public final Result get() throws InterruptedException, ExecutionException {
        return mFuture.get();
    }
    public final Result get(long timeout, TimeUnit unit) throws     InterruptedException, ExecutionException, TimeoutException {
        return mFuture.get(timeout, unit);
    }
    /**
     * 這個方法如何執行和系統版本有關,在AsyncTask的使用規則裏已經說明,若是你真的想使用並行AsyncTask,
     * 也是能夠的,只要稍做修改
     * 必須在UI線程調用此方法,5.2以後這不是必須的
     */
    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

    /**
     * 經過這個方法咱們能夠自定義AsyncTask的執行方式,串行or並行,甚至能夠採用本身的Executor
     * 爲了實現並行,咱們能夠在外部這麼用AsyncTask:
     * asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Params... params);
     * 必須在UI線程調用此方法,5.2以後這不是必須的
     */
    @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
    onPreExecute();
    mWorker.mParams = params;
    //而後後臺計算doInBackground才準備開始
    exec.execute(mFuture);
    return this;
}
/**這是AsyncTask提供的一個靜態方法,方便咱們直接執行一個runnable*/
@MainThread
public static void execute(Runnable runnable) {
    sDefaultExecutor.execute(runnable);
}
/**打印後臺計算進度,onProgressUpdate會被調用*/
@WorkerThread
protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}
//任務結束的時候會進行判斷,若是任務沒有被取消,則onPostExecute會被調用
private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}
//AsyncTask內部Handler,用來發送後臺計算進度更新消息和計算完成消息
private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }
    @Override
    public void handleMessage(Message msg) {
        AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
        switch (msg.what) {
            case MESSAGE_POST_RESULT:
                // There is only one result
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams;}
private static class AsyncTaskResult<Data> {
    final AsyncTask mTask;
    final Data[] mData;
    AsyncTaskResult(AsyncTask task, Data... data) {
        mTask = task;
        mData = data;
      }
    }
}
複製代碼

####AsynTask是如何實現串行的?post

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


 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
    onPreExecute();
    mWorker.mParams = params;
    //而後後臺計算doInBackground才準備開始
    exec.execute(mFuture);
    return this;
}
複製代碼

是否是上面看不出什麼來?那是必須的,AsyncTask實現串行是經過控制Executor .execute方法來實現的。this

private static class SerialExecutor implements Executor {
    //線性雙向隊列,用來存儲全部的AsyncTask任務
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    //當前正在執行的AsyncTask任務
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
        //將新的AsyncTask任務加入到雙向隊列中
        mTasks.offer(new Runnable() {
            public void run() {
                try {
                    r.run();//執行AsyncTask任務
                } finally {
                    /**
                     * 當前AsyncTask任務執行完畢後,進行下一輪執行,若是還有未執行任務的話
                     * 這一點很明顯體現了AsyncTask是串行執行任務的,老是一個任務執行完畢纔會執行下一個任務
                     */
                    scheduleNext();
                }
            }
        });

        //若是當前沒有任務在執行,直接進入執行邏輯
        if (mActive == null) {
            scheduleNext();
        }
    }

    //從任務隊列中取出隊列頭部的任務,若是有就交給併發線程池去執行
    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}
複製代碼

一、 當任務來臨時,首先就是加入隊列,而後判斷當前有沒有任務正在執行; 二、 若是沒有任務正在執行則直接調用scheduleNext(),執行任務。 三、 噹噹前任務執行完成又再次在finally塊調用scheduleNext執行下一個任務。這樣就實現了串行執行任務,固然串行執行任務也是使用了線程池,那還用說是吧。spa

那若是咱們想要並行,如何操做,很簡單之間替換默認的SerialExecutor ,就是由於它,才串行的,因此咱們只要像這樣就能夠實現並行執行任務了:線程

new MyAsyncTask("MyAsyncTask1").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
複製代碼

其實AsyncTask源碼並很少,文章到此結束,歡迎拍磚。

相關文章
相關標籤/搜索