AsyncTask 坑 多个task是串行执行还是并行的

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AsyncTask 坑 多个task是串行执行还是并行的相关的知识,希望对你有一定的参考价值。

参考技术A 3个泛型指的是什么呢?我们来看看AsyncTask这个抽象类的定义,当我们定义一个类来继承AsyncTask这个类的时候,我们需要为其指定3个泛型参数:

AsyncTask <Params, Progress, Result>
Params: 这个泛型指定的是我们传递给异步任务执行时的参数的类型
Progress: 这个泛型指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型
Result: 这个泛型指定的异步任务执行完后返回给UI线程的结果的类型
我们在定义一个类继承AsyncTask类的时候,必须要指定好这三个泛型的类型,如果都不指定的话,则都将其写成Void,例如:

AsyncTask <Void, Void, Void>
4个步骤:当我们执行一个异步任务的时候,其需要按照下面的4个步骤分别执行

AsyncTask 坑 AsyncTask对象多次执行

经常看到网上有这种面试题目:一个AsyncTask对象能不能被多次执行?

其实,想知道答案,最好的办法就是看文档说明,要是文档说不行那就是不行,行就是行。

如果想知道的更多,那就看代码呗。


AsyncTask的execute函数

excute是用来启动一个异步任务的API,先看看这个函数,

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

下面的这个函数里面可以看到有个成员mStatus,代码很简单,如果mStatus不是PENDING,直接丢异常。

    @MainThread
    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;
    

看看状态枚举,很简单就只有3种状态,PENDING, RUNNING, FINISHED。

   public enum Status 
        /**
         * Indicates that the task has not been executed yet.
         */
        PENDING,
        /**
         * Indicates that the task is running.
         */
        RUNNING,
        /**
         * Indicates that @link AsyncTask#onPostExecute has finished.
         */
        FINISHED,
    


看mStatus的变化流程:

1. AsyncTask对象创建的时候,初始化成PENDING.

    private volatile Status mStatus = Status.PENDING;

2. execute()里面会判断,如果不是pending(无论是running,还是finished)都直接丢出异常。只有pending才能往下走。当是pending的时候,就直接设置成running。然后就发onPreExecute通知和执行任务。

3. 执行完后,无论成功还是失败,都设置成finished。

    private void finish(Result result) 
        if (isCancelled()) 
            onCancelled(result);
         else 
            onPostExecute(result);
        
        mStatus = Status.FINISHED;
    

从这些代码,其实就可以看出,一个AsyncTask对象被创建出来后,就只能执行一个异步任务。一旦开始执行了,无论在运行过程中,还是运行结束了,都不能在重复执行了。


FutureTask

之前也看到过,AsyncTask的构造函数里面,会创建一个mWorker和mFuture。mWorker会传给mFuture,mFuture里面的成员callable就是引用了mWorker对象。

然后FutureTask一次执行完后,就会调用下面的函数,很清楚callable被赋值为null了。

    private void finishCompletion() 
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) 
            if (U.compareAndSwapObject(this, WAITERS, q, null)) 
                for (;;) 
                    Thread t = q.thread;
                    if (t != null) 
                        q.thread = null;
                        LockSupport.unpark(t);
                    
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                
                break;
            
        

        done();

        callable = null;        // to reduce footprint
    

而mFuture和mWorker都是被声明称final的

    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;

那么当一个AsyncTask对象被创建出来后,mFuture和mWorker只能被初始化一次,而mFuture执行完一次任务后,就会调用finishCompletion,然后把callable赋值成0,也就是说就算后面再执行mFuture,因为callable被清0了,任务也不会再次执行。

从种种迹象表明,一个AsyncTask对象只能执行一次任务,是google刻意限制的。

至于为什么要设计成这样?

我想Google设计AsyncTask的初衷就是:这是个轻量级的类,用于执行简单的后台操作。

一个任务就是一个AsyncTask对象,如果想执行其他任务或者同个任务再执行一次,那就再创建一个AsyncTask对象呗。





以上是关于AsyncTask 坑 多个task是串行执行还是并行的的主要内容,如果未能解决你的问题,请参考以下文章

AsyncTask 坑 多个task是串行执行还是并行的

svtask内是并行还是串行

AsyncTask 执行()或 executeOnExecutor()?

Android3.0以后,Asynctask在没开线程池的情况下会怎么排队执行

AsyncTask源码分析

AsyncTask 坑 AsyncTask对象多次执行