AsyncTask版本的差异

来源:互联网 发布:移动3g卡能用4g网络 编辑:程序博客网 时间:2024/04/29 15:25

今天我们来说说AsyncTask版本之间的差异,我们现在使用AsyncTask通常会使用如下方式:

 class DownloadTask extends AsyncTask<Void,Integer,String>{        @Override        protected String doInBackground(Void... params) {            return null;        }    }

然后我们怎么执行任务呢:

 new DownloadTask().execute();

今天我们通过源码来看看AsyncTasik版本之间的差异,我们点进去execute()这个方法:

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

我们可以看到execute()这个方法实际上是调用了executeOnExecutor(sDefaultExecutor, params)这个方法,这个方法接收两个参数,我们重点看第一个参数,这是一个Executor对象,我们看看它是在哪定义的

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

我们看到sDefaultExecutor 的值是一个常量,然后我们继续看这个常量是什么

 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

这个常量是一个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);            }        }    }

重点看scheduleNext这个方法,里面有个THREAD_POOL_EXECUTOR对象,这是什么,我们继续找

public static final Executor THREAD_POOL_EXECUTOR            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

可以看到这里使用了线程池,其中常量定义如下:

 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();    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;

这是3.0之后的AsyncTask的源代码,每次当一个任务执行完毕后,下一个任务才会得到执行,SerialExecutor模仿的是单一线程池的效果,如果我们快速地启动了很多任务,同一时刻只会有一个线程正在执行,其余的均处于等待状态。

但是之前的代码不是这样的,在Android 3.0之前是并没有SerialExecutor这个类的,那个时候是直接在AsyncTask中构建了一个sExecutor常量,并对线程池总大小,同一时刻能够运行的线程数做了规定

private static final int CORE_POOL_SIZE = 5;  private static final int MAXIMUM_POOL_SIZE = 128;  private static final int KEEP_ALIVE = 10;  ……  private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,          MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);  

可以看到,这里规定同一时刻能够运行的线程数为5个,线程池总大小为128。也就是说当我们启动了10个任务时,只有5个任务能够立刻执行,另外的5个任务则需要等待,当有一个任务执行完毕后,第6个任务才会启动,以此类推。而线程池中最大能存放的线程数是128个,当我们尝试去添加第129个任务时,程序就会崩溃。

因此在3.0版本中AsyncTask的改动还是挺大的,在3.0之前的AsyncTask可以同时有5个任务在执行,而3.0之后的AsyncTask同时只能有1个任务在执行。为什么升级之后可以同时执行的任务数反而变少了呢?这是因为更新后的AsyncTask已变得更加灵活,如果不想使用默认的线程池,还可以自由地进行配置。比如使用如下的代码来启动任务:

Executor exec = new ThreadPoolExecutor(15, 200, 10,          TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());  new DownloadTask().executeOnExecutor(exec);  

这样就可以使用我们自定义的一个Executor来执行任务,而不是使用SerialExecutor。上述代码的效果允许在同一时刻有15个任务正在执行,并且最多能够存储200个任务。

下面对AsyncTask进行一下总结:

这里写图片描述

0 0
原创粉丝点击