AsyncTask 的源碼分析

AsyncTask 的源碼分析

基礎知識學習

ThreadPoolExecutor分析

關鍵參數分析

  • corePoolSize:最大的核心線程數,默認情況下,核心線程會一直存活。
  • maximumPoolSize:線程池中最大線程數量(核心和非核心線程總數),如果活動線程數等於最大值是,後續的新任務還會被阻塞。
  • keepAliveTime:非核心線程的保留時間,超時會被回收。
  • unit:keepAliveTime參數的時間單位.
  • workQueue:任務隊列,用來存儲已經提交的任務(還未執行的),通過ThreadPoolExecutor的excute方法來提交Runnable對象,將其存儲在該參數中。
  • threadFactory:創建新線程。具體通過方法:Thread newThread(Runnable r)。

執行流程

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-l3sAkhcZ-1587131867238)(C:\Users\80261556.ADC\Desktop\線程池.jpg)]

關鍵源碼解讀

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
      //獲取當前線程池的狀態以及擁有的線程池數目,高位爲狀態,低位爲數目
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            //如果當前線程數目小於核心線程數,則創建核心線程,後面的bool類型參數爲true,代表創建核心線程
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
       //如果當前線程處於running狀態,之後往任務隊列中插入新的任務
        if (isRunning(c) && workQueue.offer(command)) {
            //之後重新檢查,如果線程池不是running狀態,則從隊列中刪除,並且reject
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
}



private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;
			
            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
}

AsyncTask 源碼解析

從execute方法調用開始,代碼如下

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



public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
    //一個task只能execute一次
        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 = sDefaultExecutor = SerialExecutor
        exec.execute(mFuture);

        return this;
}

這裏值得注意的是sDefaultExecutor這個成員變量的默認值是SerialExecutor,這是負責調度用的線程池。

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

調度線程池

關於調度的線程池代碼比較好理解,主要是將Runnable插入隊列,然後通過scheduleNext調用線程池執行隊列中的任務,每一次插入對應一次執行。

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

關於mFuture,我們只需要知道在裏面會輪流調用以下幾個方法:

doInBackground(mParams)
postResult(result)
onPostExecute(Result result)

這樣,一個task就基本走完了流程,但是很多時候我們需要去在UI線程裏面更新進度,這樣我們需要在doInBackground() 中調用 publishProgress () 。那麼這是怎麼實現的呢?

Handler

 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]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }


 private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

其核心主要是handler的使用,通過消息傳遞機制傳遞MESSAGE_POST_PROGRESS消息,可以在主線程中更新UI控件,同時我們也可以注意到改handler還有一種消息:MESSAGE_POST_RESULT,同時結合上面的代碼,我們可以發現在整個task中有三個方法是運行在主線程中的:

//所以我們也可以在這三個方法中更新UI
onCancelled(result);
onPostExecute(result);
onProgressUpdate(result.mData)

總結

綜合上述,我們可以發現AsynTask的所有對象是通過共享兩個線程池和一個handler來工作的,其職責如下表

具體 職責
SerialExecutor 任務隊列線程池,負責任務調度
THREAD_POOL_EXECUTOR 真正執行任務的線程池
InternalHandler 異步通信,實現工作線程和主線程的通信,並且實現UI更新

同時各個方法的調用順序如下:
在這裏插入圖片描述

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