AsyncTask源码分析(一)


AsyncTask从一开始用它来执行简单的异步任务,到后来抛弃,应该说用的熟的不能再熟了,但是对AsyncTask的内涵理解却不是那么清晰明了,所以还是从源码的角度重新看一下,AsyncTask到底干了些什么吧。

还是从最简单的成员变量看起吧:

//cpu数量
 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;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };


    //由于LinkedBlockingQueue实现是线程安全的,实现了先进先出等特性,是作为生产者消费者的首选,
    //LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,
    //其中主要用到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,
    //take方法在队列空的时候会阻塞,直到有队列成员被放进来。

     //容量128的阻塞队列
    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
     //执行任务的线程池
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

    /**
     * An {@link Executor} that executes tasks one at a time in serial
     * order.  This serialization is global to a particular process.
     */
     //用于任务的排队
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    //内部业务处理,继承自Handler
    private static InternalHandler sHandler;
    //实现Callable接口的静态抽象类
    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;
    //任务状态标志
    private volatile Status mStatus = Status.PENDING;

    private final AtomicBoolean mCancelled = new AtomicBoolean();
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

继续看构造方法:

 /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                //[-20,19],值越大优先级越低
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked抽象方法,子类必须重写的
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(result);
            }
        };

        //FutureTask一个可取消的异步计算,FutureTask 实现了Future的基本方法,提空 start cancel 操作,
        //可以查询计算是否已经完成,并且可以获取计算的结果。结果只可以在计算完成之后获取,
        //get方法会阻塞当计算没有完成的时候,一旦计算已经完成,那么计算就不能再次启动或是取消。

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}

我靠,开头注释就看到了这个new AsyncTask()必须在UIThread实现,这就限制了他的使用范围。
5-15行:mWorker的实现,由于WorkerRunnable是一个实现Callable接口的静态抽象类,所以new WorkerRunnable要实现call();在call()方法中,标记了mTaskInvoked= true,表示任务已经被调用,设置线程优先级为Process.THREAD_PRIORITY_BACKGROUND,然后执行doInBackground(params),最后将值传递给 postResult(result);
17-31行:初始化mFuture,重写done(),其中postResultIfNotInvoked(get());get()表示获取mWorker的call的返回值,即Result.

继续追中下去,其中涉及到的两个方法postResult,postResultIfNotInvoked

    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

    private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
}

先看一下8-14行:利用AsyncTask和result构造一个Message,然后发送出去有InnerHandler去处理,并返回result(这是不是有点坑啊,传进去,再原样返回来,图什么);
再看1-5行:当wasTaskInvoked = false的时候去执行postResult(result),由于我们在call()中已经声明mTaskInvoked=true,所以这个方法执行不到。

上面提到了InnerHandler,那就进去看看系统在里面做了什么处理:

 private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }

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

这个应该很容易理解,woker的call()方法在doInBackground()执行结束之后,就调用了postResult(result)方法,send 一个what = MESSAGE_POST_RESULT的Message,告诉程序任务可以结束了。

what = MESSAGE_POST_PROGRESS这个消息就更简单了,就是在doInBackgroud中调用了publishProgress(Progress…values),发送了这条what =MESSAGE_POST_PROGRESS的消息,用来通知任务进度,如果UI线程要实现进度的更新,就要重写 onProgressUpdate(Progress…values)方法,在UIThread更新UI;

那就接着看finish以及 和onProgressUpdate相关的publishProgress,还有cancel(),把这三个方法放一块分析,有助于理解。


    @WorkerThread
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

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

    public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
}

3-8行:不难理解,如果调用了cancel(),那么就不会发送what =MESSAGE_POST_PROGRESS的 Message,也就是onProgressUpdate()不用调用,否则可以;
10-17行:如果是调用了cancel(),那么就会回调onCancel(result)方法,并将mStatus 修改为Finished,否则就是正常执行完了任务,回调onPostExecute(result),mStatus 同样修改为Finished;

现在还剩最后一个重要方法excute(),我们继续看一下

 /**
     * Executes the task with the specified parameters. The task returns
     * itself (this) so that the caller can keep a reference to it.
     * 
     * <p>Note: this function schedules the task on a queue for a single background
     * thread or pool of threads depending on the platform version.  When first
     * introduced, AsyncTasks were executed serially on a single background thread.
     * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
     * to a pool of threads allowing multiple tasks to operate in parallel. Starting
     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
     * executed on a single thread to avoid common application errors caused
     * by parallel execution.  If you truly want parallel execution, you can use
     * the {@link #executeOnExecutor} version of this method
     * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
     * on its use.
     *
     * <p>This method must be invoked on the UI thread.
     */
 @MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}


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

首先看一下说明:AsyncTask最开始是设计为串行单线程执行的,从OUNUT开始,设计为一个线程池,允许多个任务并行操作,从HONEYCOMB开始又回到了串行单线程,这真是一波三折啊。
28-38行:检查AsyncTask状态,如果正在RUNNING,就不能执行execute(),如果是FINISHED,也不能执行execute(),因为一个AsyncTask只能执行一次execute()方法。
40行:标记task状态为Running;
42行:任务执行前的准备工作,可以复写onPreExecute()
44-45行:把params传递给mWorker,Executor执行execute(mFuture)执行任务,这里其实是执行的SerialExecutor.execute(mFuture);

这里还有一个不知所云的鬼就是sDefaultExecutor,我们看一下他的相关内容

 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

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

如果此时有10个任务同时调用execute(s synchronized)方法,第一个任务入队,然后在mActive = mTasks.poll()) != null被取出,并且赋值给mActivte,然后交给线程池去执行。然后第二个任务入队,但是此时mActive并不为null,并不会执行scheduleNext();所以如果第一个任务比较慢,10个任务都会进入队列等待;真正执行下一个任务的时机是,线程池执行完成第一个任务以后,调用Runnable中的finally代码块中的scheduleNext,所以虽然内部有一个线程池,其实调用的过程还是线性的。一个接着一个的执行,相当于单线程。(这是不是有点那啥)

测试一下:


public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i = 1 ;i <= 10 ; i++)
        {
            new MyAsyncTask2().execute();
        }

    }


    private class MyAsyncTask2 extends AsyncTask<Void,Void, Void>
    {

        @Override
        protected Void doInBackground(Void... params)
        {
            try
            {
                Log.e("mess", Thread.currentThread().getName()+",cpu:"+Runtime.getRuntime().availableProcessors());
                Thread.sleep(100);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            return null;
        }

    }
}

看一下打印结果 我是4.2.2的手机:

11-29 00:25:54.230    4740-4778/project.charles.com.myapplication E/mess﹕ AsyncTask #1,cpu:2
11-29 00:25:54.350    4740-4783/project.charles.com.myapplication E/mess﹕ AsyncTask #2,cpu:2
11-29 00:25:55.038    4740-4786/project.charles.com.myapplication E/mess﹕ AsyncTask #3,cpu:2
11-29 00:25:55.146    4740-4789/project.charles.com.myapplication E/mess﹕ AsyncTask #4,cpu:2
11-29 00:25:55.242    4740-4790/project.charles.com.myapplication E/mess﹕ AsyncTask #5,cpu:2
11-29 00:25:55.354    4740-4790/project.charles.com.myapplication E/mess﹕ AsyncTask #5,cpu:2
11-29 00:25:55.450    4740-4790/project.charles.com.myapplication E/mess﹕ AsyncTask #5,cpu:2
11-29 00:25:55.554    4740-4790/project.charles.com.myapplication E/mess﹕ AsyncTask #5,cpu:2
11-29 00:25:55.658    4740-4790/project.charles.com.myapplication E/mess﹕ AsyncTask #5,cpu:2
11-29 00:25:55.758    4740-4790/project.charles.com.myapplication E/mess﹕ AsyncTask #5,cpu:2

首先看线程数,符合预期结果,是根据cpu计算的,再看确实是串行单线程执行的,并且只复用了最后一个线程。

如有不对的地方,欢迎大大们指正。

猜你喜欢

转载自blog.csdn.net/baidu_17508977/article/details/53386653