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更新

同时各个方法的调用顺序如下:
在这里插入图片描述

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