AsyncTask源码分析

前言

AsyncTask在Android编程中是一种常用的异步编程方式,那么AsyncTask到底是什么呢?下面我们从
基本使用到源码分析对AsyncTask作一个全面的了解。

一般使用

通常我们对AsyncTask的使用是

//1.实现抽象类AsyncTask
Class MyAsyncTask extends AsyncTask{

  @Override  
  protected Object doInBackground(Object[] params) {  
       return null;  
  }  
}
//2.创建实例对象
MyAsyncTask myAsyncTask = New MyAsyncTask();
//3.调用execute方法执行任务
myAsyncTask.execute();

一般使用比较简单,通过实现AsyncTask抽象类,然后创建一个这样的子类实例,然后调用execute方法就可以在doInBackground进行异步处理了。

源码分析

我们看看execute方法的具体实现(这里针对Android-23源码分析的,不同版本的源码实现的方式可能不同,这里不一一分类了)

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

一句代码,我们看看executeOnExecutor方法的具体实现

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

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

首先检测mState的状态,如果同一个AsyncTask实例在没有pending的情况下,再进行execute,那么会报出相应的异常;然后去设置mState的状态,调用onPreExecute,去执行exec.execute(mFuture),最终的执行在这里。那么我们看看刚才传进来的sDefaultExecutor参数。

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

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

实质上是调用SerialExecutor 类的execute方法,首先向mTasks 提交offer队列的末尾,然后从mTasks 的头部poll出要执行的runnable.

从名字就可以看出,默认情况下,多个task是加到mTask后执行的。也就是串行执行的。如果要并行执行的画,通过executeOnExecutor(Async.THREAD_POOL_EXECUTOR,params);
关于doInBackground、onPreExecute、onPostExecute、onProgressUpdate等几个抽象方法的调线程和时期关系,不想做太多分析,都是模版设计模式思想,在不同地方调用罢了。比较简单。这里主要将线程池,这里才是AsyncTask的精华所在,以及以后在Android系统使用单独的线程池时候有个很好的参照。

线程池参数解释

 private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
 private static final int KEEP_ALIVE = 1;

 private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);
 public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

corePoolSize: 核心线程数目,即使线程池没有任务,核心线程也不会终止(除非设置了allowCoreThreadTimeOut参数)可以理解为“常驻线程”

maximumPoolSize: 线程池中允许的最大线程数目;一般来说,线程越多,线程调度开销越大;因此一般都有这个限制。

keepAliveTime: 当线程池中的线程数目比核心线程多的时候,如果超过这个keepAliveTime的时间,多余的线程会被回收;这些与核心线程相对的线程通常被称为缓存线程

unit: keepAliveTime的时间单位

workQueue: 任务执行前保存任务的队列;这个队列仅保存由execute提交的Runnable任务

threadFactory: 用来构造线程池的工厂;一般都是使用默认的;

handler: 当线程池由于线程数目和队列限制而导致后续任务阻塞的时候,线程池的处理方式。

线程池核心调度思想

那么,当一个新的任务到达的时候,线程池中的线程是如何调度的呢?

  • 如果线程池中线程的数目少于corePoolSize,就算线程池中有其他的没事做的核心线程,线程池还是会重新创建一个核心线程;直到核心线程数目到达corePoolSize(常驻线程就位)
  • 如果线程池中线程的数目大于或者等于corePoolSize,但是工作队列workQueue没有满,那么新的任务会放在队列workQueue中,按照FIFO的原则依次等待执行;(当有核心线程处理完任务空闲出来后,会检查这个工作队列然后取出任务默默执行去)
  • 如果线程池中线程数目大于等于corePoolSize,并且工作队列workQueue满了,但是总线程数目小于maximumPoolSize,那么直接创建一个线程处理被添加的任务。
  • 如果工作队列满了,并且线程池中线程的数目到达了最大数目maximumPoolSize,那么就会用最后一个构造参数handler处理;默认的处理方式是直接丢掉任务,然后抛出一个异常。

具体的实现场景描述:当有新的任务要处理时,先看线程池中的线程数量是否大于 corePoolSize,再看缓冲队列 workQueue 是否满,最后看线程池中的线程数量是否大于 maximumPoolSize。另外,当线程池中的线程数量大于 corePoolSize 时,如果里面有线程的空闲时间超过了 keepAliveTime,就将其移除线程池,这样,可以动态地调整线程池中线程的数量。

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