AsyncTask源碼簡析

(源碼來自sdk7.0)
構造方法
構造方法有3個

/**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        this((Looper) null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Handler handler) {
        this(handler != null ? handler.getLooper() : null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Looper callbackLooper) {

第3個構造是主要構造,但被隱藏了。應用層常用到的是無參構造即傳入一個null至該構造,實際等價於傳入MainLooper。

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

但是這裏的主線程looper和非主線程looper實際上是分開處理的,非主線程需要自己處理不同message的結果的分發,而主線程的源碼中完全替你封裝好了。

主線程的mHandler初始化getMainHandler

    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

這個InternalHandler就是做了MESSAGE_POST_RESULT和MESSAGE_POST_PROGRESS的主線程回調

因爲靜態內部類在假泛型中無法獲取到泛型類型,而暴露給API的

protected void onProgressUpdate(Progress... values)

protected void onPostExecute(Result result)

顯然希望使用到泛型約束。這裏不得已用了unchecked屏蔽編譯錯誤。因爲每個AsyncTask的只能執行一次,這裏的類型安全是沒問題的~~~ 就是代碼可讀性稍差,

    private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @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]); //主線程調用被複寫的onCancel或者onPostExecute
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData); //主線程調用被複寫的onProgressUpdate
                    break;
            }
        }
    }

構造方法中除了創建了handler,更重要的是初始化了FutureTask

        mWorker = new WorkerRunnable<Params, Result>() {  //WorkRunnable其實就是個Callback的實現,靜態內部類存放Params規避內存泄漏
            public Result call() throws Exception {
                mTaskInvoked.set(true);  //mTaskInvoked在call第一行用於標識任務已經被執行。在done中調用postResultIfNotInvoked提取判斷
                                         //因爲done()函數如果在future的cancel時是由調用線程執行的 可能存在線程安全問題
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams); //子線程執行執行復寫的doInBackground任務
                    Binder.flushPendingCommands(); //以下是該靜態函數的api註釋
/*將當前線程中掛起的所有Binder命令都刷新到內核驅動。
這可以在執行可能阻塞很長時間的操作之前調用,
以確保任何掛起的對象引用已經被釋放。
這樣可以防止這一耗時過程的持續時間超過對象應有的生命週期。*/
                } catch (Throwable tr) {
                    mCancelled.set(true); //這裏也是一個AtomicBoolean 標識cancel
                    throw tr;
                } finally {
                    postResult(result);//mTaskInvoked被設置爲true這句代碼執行之後,就保證了final中調用postResult
                }
                return result;
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());//future阻塞get()獲取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);
                }
            }
        }

這裏有個小疑問,mTaskInvoked是一個AtomicBoolean,保證多線程的原子性,但是這裏並沒有調用compareAndSet方法,那麼使用原子類的意義在哪裏呢? 這裏在我的理解裏 應該只需要聲明volatile boolean mTaskInvoked就可以了,如有高見歡迎討論。

postResultIfNotInvoked函數的意義,當future沒有執行就被cancel後,cancel調用done()函數,獲得到get()將是一個空,這時進入!wasTaskInvoked流程 postResult(null)

private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

線程調度

異步任務啓動的入口

    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    @MainThread
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) { //這段代碼保證AsyncTask只能被執行一次
            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; //配置參數給Callback
        exec.execute(mFuture); //全局調度執行器 接管futrue

        return this;
    }
不管我們通常調用的execute(Params... params)

還是提供給我們直接運行一個runnable的

    @MainThread
    public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }

實際都是使用全局調度執行器sDefaultExecutor進行處理,它的默認實現是一個串行的分發

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

在主線程調用

並且他的實現保證了串行:全局中多個AsyncTask被execute,只會有deque頭部那個成爲mActive,依序執行

    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() { //offer插入ruunable到deque的尾部
                //代理包裝了r 實際執行是由線程池做的 這裏只是添加了 調度工作的代理層
                public void run() {
                    try {  //這樣try catch 不阻礙異常的拋出 同時又能保證 一個runnable執行完之後 一定執行下一個
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) { //塞進隊列後檢查:如果現在沒有執行的runnable 那麼開始幹活了
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() { //這個函數執行時機在1、deque從空到有時 與2、sWorkExecutor有runnable執行完畢時調用
            if ((mActive = mTasks.poll()) != null) { //頭部取出 開始執行
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

線程池

我們看到了真正消費mTasks中的Runnable的是THREAD_POOL_EXECUTOR.execute(mActive) 

他是一個全局的executor

    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的 可以直接設置。缺省值爲一個核心線程cpu-1、最大線程2倍cpu、非核心線程待活時間10秒、等待工作隊列長度128的線程池

超出工作隊列的拒絕策略用的是java缺省的拋異常RejectedExecutionException

    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

可以關注一下線程工廠的計數器 用的是原子類AtomicInt的自增

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





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