AsyncTask裏的線程池串行、並行邏輯詳解。

AsyncTask裏面封裝了線程池和Handler,所以很是方便我們使用它來處理ui線程和工作線程之間的異步任務的邏輯工作。

AsyncTask裏面的的線程池的實現是用ThreadPoolExecutor來實現的。然而ThreadPoolExecutor的的執行邏輯在cpu多核情況下,執行順序是不確定的,也就是並行的。

AsyncTask裏面有兩個線程池的靜態常量 這就保證了整個邏輯內只有一個線程池。

  • THREAD_POOL_EXECUTOR 多核下,並行,單核下串行。
  • SERIAL_EXECUTOR,單核和多核下都是串行。

下面是THREAD_POOL_EXECUTOR的實現和定義。

    /**
     * An {@link 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, new ThreadPoolExecutor.DiscardOldestPolicy());
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

下面是SERIAL_EXECUTOR的實現。SERIAL_EXECUTOR的實現是基於THREAD_POOL_EXECUTOR,但加入了串行邏輯。具體的實現邏輯全在scheduleNext這個方法裏面。如下。

   private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    
    /**
     * 一個{@link Executor},按串行順序一次執行一個任務。這種序列化對於特定的流程是全局的。
     */
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    /**
     * 串行Executor,基於THREAD_POOL_EXECUTOR實現串行
     */
    private static class SerialExecutor implements Executor {
        /**
         * 串行任務的雙端隊列
         */
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        @Override
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                @Override
                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);
            }
        }
    }
   

AsyncTask提供了幾個執行方法。

1,串行。AsyncTask提供了靜態方法execute,直接傳入Runnable對象,進行串行執行,注意該方法需要在UI線程中調用

                    AsyncTask.execute(new Runnable() {
                        @Override
                        public void run() {
                            //異步邏輯
                        }
                    });

看一下靜態方法execute的源碼,使用的是默認的sDefaultExecutor執行的。

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

默認情況下,sDefaultExecutor的默認值是SERIAL_EXECUTOR。而SERIAL_EXECUTOR是實現是AsyncTask的靜態內部類SerialExecutor。SerialExecutor的實現是串行的。所以,默認情況下sDefaultExecutor的行爲是串行的。

2,串行,AsyncTask還提供了一個execute成員方法。裏面調用的executeOnExecutor成員方法傳入的是sDefaultExecutor線程池,

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

再看executeOnExecutor方法。

    @MainThread
    public final MyAsyncTask<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;
    }

3,串行,並行隨你選。

executeOnExecutor方法支持你指定線程池。傳入THREAD_POOL_EXECUTOR並行,傳入SERIAL_EXECUTOR串行。

 

 

 

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