AsyncTask基本原理

来源:互联网 发布:数据采集系统应用领域 编辑:程序博客网 时间:2024/04/26 14:47

概述

AsyncTask用于简化UI线程的使用,可以将工作线程的结果更新到UI线程,而不需要显式使用ThreadHandler

官方文档对AsyncTask用途的描述:

AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.

翻译:

AsyncTask被设计为ThreadHandler的辅助类,并不是线程框架的组成部分。AsyncTask应该被用于短时间的操作(最多几秒钟)。如果希望让一个线程长时间工作,建议使用java.util.concurrent 包中的其他API,比如ExecutorThreadPoolExecutorFutureTask

串并行

官方文档对串并行的描述:

When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.

翻译:

最开始引入时是串行执行,Android 1.6改用线程池进行并行执行,Android 3.0开始又改回串行执行。

Android 3.0之后采用串行,指的是AsyncTask默认的执行方式是串行,即AsyncTask.execute()方法会调用静态成员SERIAL_EXECUTOR执行任务,如果用户确实需要并行实现,可以显示调用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params),这样就会使用线程池执行。

工作原理

以下都按照Android 3.0之后进行分析。

  • FutureTask mFutrue
    实现了Callable接口,是实际需要执行的任务,它的call()方法里会调用doInBackground(),并将结果以AsyncTaskResult的形式,装进Message,通过Handler发送到主线程的消息队列。

  • WorkerRunnable mWorker
    实现了RunnableFuture接口,是对mFuture的进一步封装,供Executor执行。

  • static Executor SERIAL_EXECUTOR
    顺序执行器,内部并没有新线程,并不负责执行具体任务,它的execute()只负责把要执行的Runnable对象放入队列mTasks,而且还会对这个Runnable附加一个动作,即执行完run()方法后自动取下一个方法执行。这部分的源码在下面。

  • static Executor THREAD_POOL_EXECUTOR
    这才是实际执行任务的线程池,启动后,从mTasks取出Runnable并执行。由于SERIAL_EXECUTOR对队列中的Runnable对象都做了处理,所以,执行完一个任务会自动执行下一个。

也就是说,虽然THREAD_POOL_EXECUTOR是一个线程池,但在默认情况下,也就是调用execute()时,它内部只会产生一个线程,由这个线程去串行执行所有的任务。只有当显示调用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params)时,才会有多个工作线程产生。由于这种串行的特性,AsyncTask并不适合执行长时间的任务。

源码

为便于理解,放上SERIAL_EXECUTOR代码:

private static class SerialExecutor implements Executor {    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();    Runnable mActive;    public synchronized void execute(final Runnable r) {        // 只把Runnable放入队列,并不执行        mTasks.offer(new Runnable() {            public void run() {                try {                    r.run();                } finally {                    // 由于附加了这个动作,THREAD_POOL_EXECUTOR在执行完一个Runnable之后就会自动执行下一个Runnable                    // 所以说现在的AsyncTask是串行执行的                    scheduleNext();                }            }        });        if (mActive == null) {            scheduleNext();        }    }    protected synchronized void scheduleNext() {        if ((mActive = mTasks.poll()) != null) {            // 具体的执行任务都交给THREAD_POOL_EXECUTOR处理            THREAD_POOL_EXECUTOR.execute(mActive);        }    }}
0 0
原创粉丝点击