Android中的多线程之AysncTask原理分析

AsyncTask是一个抽象类,它是由Android封装的一个轻量级异步类,它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。

首先我们看看它的定义:

public abstract class AsyncTask

3种泛型类型分别表示参数类型,后台任务执行的进度类型,返回的结果类型,如果某个参数不需要,可以设置为void。

一个异步任务的执行一般包括以下几个步骤:
- execute(Params… params):执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
- onPreExecute():在execute方法被调用后立即执行,执行在UI线程,一般用来在执行后台任务之前对UI做一些标记。
- doInBackground(Params… params):在onPreExecute()方法完成后立即执行,用于执行较为耗时的操作,此方法将接收输入参数和返回结果计算。在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。
- onProgressUpdate(Progress… values):执行在UI现在。在调用publishProgress(Progress... values)时,此方法被执行。直接将进度信息更新到UI组件上。
- onPostExecute(Result result):执行在UI线程。当后台操作结束时,此方法将会被调用,doInBackground方法返回的计算结果将作为参数传递到此方法中,直接将结果显示到UI组件上。

先通过一个下载图片的小例子来体验它:

public class AsyncDemo extends AsyncTask{


    private String mUrl;
    private onDownLoadInterface mCallback;

    public interface onDownLoadInterface{
        void onStarting();
        void onFinish(Bitmap bitmap);
    }

    public AsyncDemo(onDownLoadInterface callback){
        mCallback = callback;
    }

    @Override
    protected void onPreExecute() {
        mCallback.onStarting();
    }

    @Override
    protected Bitmap doInBackground(String... strings) {
        mUrl =strings[0];
        Bitmap bitmap = null;
        URLConnection connection;
        InputStream in;
        try {

            connection = new URL(mUrl).openConnection();
            in = connection.getInputStream();

            //为了看到效果
            Thread.sleep(2000);

            BufferedInputStream bis =
                    new BufferedInputStream(in);
            bitmap = BitmapFactory.decodeStream(bis);
            in.close();
            bis.close();

        }catch (MalformedURLException e){

            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        mCallback.onFinish(bitmap);
    }
}



         AsyncDemo asyncDemo = new AsyncDemo(this);
        asyncDemo.execute(URL);



    @Override
    public void onStarting() {
        dialog = new AlertDialog.Builder(this)
                .setMessage("图片正在下载")
                .setTitle("下载")
                .create();
        dialog.show();
    }


    @Override
    public void onFinish(Bitmap bitmap) {
        dialog.dismiss();
        mImageView.setImageBitmap(bitmap);
    }

然后我们就可以下载一张图片,效果如图:

Android中的多线程之AysncTask原理分析_第1张图片

那么它下载这一张图片,经历了什么呢?

首先我们先看看AsyncTask里面的几个核心的方法:

//执行在工作线程
 @WorkerThread
    protected abstract Result doInBackground(Params... params);

//执行在DoInBackground之前,并且执行在UI线程
 @MainThread
    protected void onPreExecute() {
    }

    // 后台操作执行完会调用的方法,在此更新UI
    @MainThread
    protected void onPostExecute(Result result) {
    }

    //在此更新进度
    @MainThread
    protected void onProgressUpdate(Progress... values) {
    }


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

    //执行任务,注意excute方法必须在UI线程中调用
    //exec :执行任务的线程池
     @MainThread
    public final AsyncTask executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
        //检测状态,只有在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();
        //UI线程,传递过来的参数
        mWorker.mParams = params;
        //交给线程池管理器进行调度,参数为FutureTask类型
        exec.execute(mFuture);

        return this;
    }

    //发布进度
     @WorkerThread
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult(this, values)).sendToTarget();
        }
    }

在上面代码中,我们看到有一个Stauts的枚举类,Status枚举类代表了AsyncTask的状态:

public enum Status {
        /**
         * 未执行状态
         */
        PENDING,
        /**
         *执行中
         */
        RUNNING,
        /**
         * 执行完成
         */
        FINISHED,
    }

在调用execute方法时,如果是非PENDING状态则会抛出异常,这也就解释了为什么一个AsyncTask实例只能那个运行一次。

在execute方法中,涉及到了三个变量:sDefaultExecutor,mWork,mFuture:

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    private final WorkerRunnable mWorker;
    private final FutureTask mFuture;

    private static class SerialExecutor implements Executor
  • sDefaultExecutor:它是ThreadPoolExecutor的实例,用于管理提交给AsyncTask的任务:
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();

    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//核心线程数
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//最大线程数
    private static final int KEEP_ALIVE_SECONDS = 30;//线程空闲时留存的时间

    //线程工厂
     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());
        }
    };

    //任务队列
    private static final BlockingQueue sPoolWorkQueue =
            new LinkedBlockingQueue(128);
    //线程池
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
    //静态块创建线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

    //默认的任务调度是顺序执行
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    //顺序执行的Executor
     private static class SerialExecutor implements Executor {
        final ArrayDeque mTasks = new ArrayDeque();
        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);
            }
        }
    }

从上述代码中我们可以看到,sDefaultExecutor只负责将异步任务分发给THREAD_POOL_EXECUTOR线程池,因此真正执行任务的地方是THREAD_POOL_EXECUTOR。

  • mWork 和mFuture
/**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Looper callbackLooper) {
        //得到在UI线程中的Handler
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        //WorkRunnable是AsyncTask的一个抽象内部类
        mWorker = new WorkerRunnable() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //执行DoInBackground
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    //最后将结果投递到UI线程
                    postResult(result);
                }
                return result;
            }
        };
        //mFuture会调用mWork做后台任务,完成后会调用done方法
        mFuture = new FutureTask(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 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(this, result));
        message.sendToTarget();
        return result;
    }


private static abstract class WorkerRunnable implements Callable {
        Params[] mParams;
    }

我们可以看到在mWork中会通过postResult将结果投递出去,但是如果期间发生了异常,postResult将不会调用,那么最终在Future的done方法中通过postResultIfNotInvoked检查是否执行成功,如果执行成功且未调用postResult,那么就调用postResult,否则忽略该执行结果.

在创建AsyncTask对象后,我们会执行AsyncTask的execute方法:

 @MainThread
    public final AsyncTask execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    、
      @MainThread
    public final AsyncTask 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;
    }

//sDefaultExecutor是SerialExecutor实例
private static class SerialExecutor implements Executor {
    //双端队列
        final ArrayDeque mTasks = new ArrayDeque();
        Runnable mActive;
        //mFuture实现了Runnable
        public synchronized void execute(final Runnable r) {
            //将Runnable对象放入队列
            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);
            }
        }
    }

execute方法接收一个Runnable对象,我们传入的mFuture正好实现了该接口,方法内部首先通过双端队列ArrayDeque的offer方法把一个新创建的Runnable对象入队。然后判断mActive是否为空?第一次执行肯定是为空的,所以会调用scheduleNext方法,scheduleNext方法首先从双端队列中得到一个元素,如果不为空,就调用THREAD_POOL_EXECUTOR.execute方法,THREAD_POOL_EXECUTOR是一个线程池,也就是说我们把从双端队列中得到的任务交给线程池去执行(接下来的代码都在工作线程中执行)

还记得,上面我们看到THREAD_POOL_EXECUTOR是ThreadPoolExecutor的实例(ThreadPoolExecutor实现了Excutor):

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

之前的博客中有分析过这段代码,这段代码的主要功能其实就是将异步任务加入将要执行的队列。

 private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            //得到运行状态和活动线程数
            int c = ctl.get();
            //得到线程池的状态
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                //得到活动线程数
                int wc = workerCountOf(c);
                //boolean类型的core,true表示在新增线程时会判断当前活动线程数是否少于corePoolSize,
               // false表示新增线程前需要判断当前活动线程数是否少于maximumPoolSize
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))//检查是否可以新增线程
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);//生成一个Work对象,同时 生成一个新线程
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);//将w添加到works里,这是一个HashSet集合对象
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {//如果添加成功,就异步执行该任务。在这里就是启动了mFuture任务
                    t.start();//线程启动,那么则会调用到run方法。在这里就是调用了mFuture的run方法
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

     Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

我们可以分析到,线程池在execute一个任务的时候,先是判断是否可以加入任务队列,如果可以,就新建一个线程对任务进行执行,其实也就是调用任务的run方法

public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            //在构造mFuture的时候,传入了一个mWork,也就是callable,
            //mWork是Callable的实例,Callble的call方法是可以返回结果的
            Callable c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    //在这里就是调用mWork的calll方法,得到结果.
                    //在mWork的call方法中,会调用doInBackground方法
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                //如果发送异常
                    result = null;
                    ran = false;
                    //调用setException方法,会调用done方法
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

     mWorker = new WorkerRunnable() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();//释放
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);//投递结果给UI线程
                }
                return result;
            }
        };


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

 public void sendToTarget() {
        target.sendMessage(this);//target就是Handler
    }


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

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

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

最后,一张流程图附上:
Android中的多线程之AysncTask原理分析_第2张图片

分享一张图:

Android中的多线程之AysncTask原理分析_第3张图片

你可能感兴趣的:(android)