AsyncTask详解

AsyncTask详解

标签: asynchronousasynctask
2014-05-25 23:27 1328人阅读 评论(0) 收藏 举报
AsyncTask详解 分类:

目录(?)[+]

        作为Android中最常用跨线程手段之一,AsyncTask经常出现在代码中。我也经常使用AsyncTask,有一次遇到一个奇怪的情况:AsyncTask.execute()函数调用后,AsyncTask却未立即执行,而是过了一段时间以后,才开始执行,当时觉得很奇怪,一番Google后,得知是线程池的原因。事后也一直搁着,直到今天工作有点空,花了点时间看看AsyncTask的实现。

AsyncTask的线程池

        AsyncTask提供了两个线程池,用以执行后台任务:

AsyncTask详解

        当然,开发者也可以通过自定义线程池来执行后台任务:

AsyncTask详解


THREAD_POOL_EXECUTOR

        THREAD_POOL_EXECUTOR的定义为:

[java] view plain copy
  1. /** 
  2.  * An {@link Executor} that can be used to execute tasks in parallel. 
  3.  */  
  4. public static final Executor THREAD_POOL_EXECUTOR  
  5.         = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,  
  6.                 TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);  
        其中用到的一些参数如下:

[java] view plain copy
  1. private static final int CORE_POOL_SIZE = 5;  
  2. private static final int MAXIMUM_POOL_SIZE = 128;  
  3. private static final int KEEP_ALIVE = 1;  
  4.   
  5. private static final ThreadFactory sThreadFactory = new ThreadFactory() {  
  6.     private final AtomicInteger mCount = new AtomicInteger(1);  
  7.   
  8.     public Thread newThread(Runnable r) {  
  9.         return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());//创建一个拥有特定名字的线程  
  10.     }  
  11. };  
  12.   
  13. private static final BlockingQueue<Runnable> sPoolWorkQueue =  
  14.         new LinkedBlockingQueue<Runnable>(10);  
        这里不详细解释ThreadPoolExecutor的实现,而是简单介绍下ThreadPoolExecutor的工作逻辑(线程池的工作逻辑,相信大家都比较清楚)

  1. 当线程池内无空闲线程,且线程数不足CORE_POOL_SIZE时,创建新的线程来执行任务。
  2. 当线程池内无空闲线程,且线程数大于等于CORE_POOL_SIZE,且sPoolWorkQueue为满时,把任务放到sPoolWorkQueue中。
  3. 当线程池内无空闲线程,且线程数大于等于CORE_POOL_SZIE,且sPoolWorkQueue已满,且线程数未达到MAXIMUM_POOL_SIZE时,创建新线程以执行任务。
  4. 当线程池内无空闲线程,且线程数大于等于CORE_POOL_SZIE,且sPoolWorkQueue已满,且线程数等于MAXIMUM_POOL_SIZE时,抛出异常。

       从当前的参数我们可以看到,THREAD_POOL_EXECUTOR最多同时拥有128个线程执行任务,通常情况下(sPoolWorkQueue有任务,且未满),THREAD_POOL_EXECUTOR会拥有5条线程同时处理任务。


SERIAL_EXECUTOR

        默认情况下,AsyncTask会在SERIAL_EXECUTOR中执行后台任务(其实,这个说法不太准确,稍后解释):

[java] view plain copy
  1. private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;          
        SERIAL_EXECUTOR的定义为:

[java] view plain copy
  1. /** 
  2.  * An {@link Executor} that executes tasks one at a time in serial 
  3.  * order.  This serialization is global to a particular process. 
  4.  */  
  5. public static final Executor SERIAL_EXECUTOR = new SerialExecutor();  

        而SerialExecutor的定义为:
[java] view plain copy
  1. private static class SerialExecutor implements Executor {  
  2.     final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();  
  3.     Runnable mActive;  
  4.   
  5.     public synchronized void execute(final Runnable r) {  
  6.         mTasks.offer(new Runnable() {  
  7.             public void run() {  
  8.                 try {  
  9.                     r.run();  
  10.                 } finally {  
  11.                     scheduleNext();  
  12.                 }  
  13.             }  
  14.         });  
  15.         if (mActive == null) {  
  16.             scheduleNext();  
  17.         }  
  18.     }  
  19.   
  20.     protected synchronized void scheduleNext() {  
  21.         if ((mActive = mTasks.poll()) != null) {  
  22.             THREAD_POOL_EXECUTOR.execute(mActive);  
  23.         }  
  24.     }  
  25. }  
        从这里,我们可以看到SerialExecutor并不是一个线程池(所以本文前面说AsyncTask的两个线程池的说法是不准确的),它实际上是提供了一个mTask来储存所有待执行的task,并逐个提交给THREAD_POOL_EXECUTOR执行。
       所以,实际上所有的后台任务都是在THREAD_POOL_EXECUTOR中执行的,而
[java] view plain copy
  1. AsyncTask.execute()  
        和
[java] view plain copy
  1. AsyncTask.executorOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)  
        的差别在于,前者会逐个执行任务,同一时间仅有一个任务被执行。

AsyncTask的实现

        AsyncTask的实现,需要依赖于两个成员:

[java] view plain copy
  1. private final WorkerRunnable<Params, Result> mWorker;  
  2. private final FutureTask<Result> mFuture;  

WorkerRunnable

        WorkerRunnable的定义为:

[java] view plain copy
  1. private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {  
  2.     Params[] mParams;  
  3. }  
        而Callable的定义为:

[java] view plain copy
  1. public interface Callable<V> {  
  2.     /** 
  3.      * Computes a result, or throws an exception if unable to do so. 
  4.      * 
  5.      * @return computed result 
  6.      * @throws Exception if unable to compute a result 
  7.      */  
  8.     V call() throws Exception;  
  9. }  
         WorkerRunnable为抽象类,所以使用的其实是它的子类:

[java] view plain copy
  1. /** 
  2.   * Creates a new asynchronous task. This constructor must be invoked on the UI thread. 
  3.   */  
  4.  public AsyncTask() {  
  5.      mWorker = new WorkerRunnable<Params, Result>() {  
  6.          public Result call() throws Exception {  
  7.              mTaskInvoked.set(true);  
  8.   
  9.              Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  10.              //noinspection unchecked  
  11.              return postResult(doInBackground(mParams));  
  12.          }  
  13.      };  
  14.   
  15.      mFuture = new FutureTask<Result>(mWorker) {  
  16.          @Override  
  17.          protected void done() {  
  18.              try {  
  19.                  postResultIfNotInvoked(get());  
  20.              } catch (InterruptedException e) {  
  21.                  android.util.Log.w(LOG_TAG, e);  
  22.              } catch (ExecutionException e) {  
  23.                  throw new RuntimeException("An error occured while executing doInBackground()",  
  24.                          e.getCause());  
  25.              } catch (CancellationException e) {  
  26.                  postResultIfNotInvoked(null);  
  27.              }  
  28.          }  
  29.      };  
  30.  }  

         call函数的重载挺简单,主要就是调用doInBackground函数,执行后台任务。


FutureTask

        FutureTask的实现比WorkerRunnable复杂,但是,如果抓住核心去分析也很简单。

        首先, FutureTask实现了RunnableFuture接口:

[java] view plain copy
  1. public class FutureTask<V> implements RunnableFuture<V> {  
        然后,RunnableFuture继承自Runnable:
[java] view plain copy
  1. public interface RunnableFuture<V> extends Runnable, Future<V> {  
  2.     /** 
  3.      * Sets this Future to the result of its computation 
  4.      * unless it has been cancelled. 
  5.      */  
  6.     void run();  
  7. }  
        所以,FutureTask类,肯定实现了run方法:
[java] view plain copy
  1. public void run() {  
  2.      if (state != NEW ||  
  3.          !UNSAFE.compareAndSwapObject(this, runnerOffset,  
  4.                                       null, Thread.currentThread()))  
  5.          return;  
  6.      try {  
  7.          Callable<V> c = callable;  
  8.          if (c != null && state == NEW) {  
  9.              V result;  
  10.              boolean ran;  
  11.              try {  
  12.                  result = c.call();  
  13.                  ran = true;  
  14.              } catch (Throwable ex) {  
  15.                  result = null;  
  16.                  ran = false;  
  17.                  setException(ex);  
  18.              }  
  19.              if (ran)  
  20.                  set(result);  
  21.          }  
  22.      } finally {  
  23.          // runner must be non-null until state is settled to  
  24.          // prevent concurrent calls to run()  
  25.          runner = null;  
  26.          // state must be re-read after nulling runner to prevent  
  27.          // leaked interrupts  
  28.          int s = state;  
  29.          if (s >= INTERRUPTING)  
  30.              handlePossibleCancellationInterrupt(s);  
  31.      }  
  32.  }  
        忽略其他处理,run函数执行了callable的call函数。再说说callable是什么东西:
[java] view plain copy
  1. public FutureTask(Callable<V> callable) {  
  2.     if (callable == null)  
  3.         throw new NullPointerException();  
  4.     this.callable = callable;  
  5.     this.state = NEW;       // ensure visibility of callable  
  6. }  
      在看看前面已经介绍过的AsyncTask构造函数:
[java] view plain copy
  1. /** 
  2.    * Creates a new asynchronous task. This constructor must be invoked on the UI thread. 
  3.    */  
  4.   public AsyncTask() {  
  5.       mWorker = new WorkerRunnable<Params, Result>() {  
  6.           public Result call() throws Exception {  
  7.               mTaskInvoked.set(true);  
  8.   
  9.               Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  10.               //noinspection unchecked  
  11.               return postResult(doInBackground(mParams));  
  12.           }  
  13.       };  
  14.   
  15.       mFuture = new FutureTask<Result>(mWorker) {  
  16.           @Override  
  17.           protected void done() {  
  18.               try {  
  19.                   postResultIfNotInvoked(get());  
  20.               } catch (InterruptedException e) {  
  21.                   android.util.Log.w(LOG_TAG, e);  
  22.               } catch (ExecutionException e) {  
  23.                   throw new RuntimeException("An error occured while executing doInBackground()",  
  24.                           e.getCause());  
  25.               } catch (CancellationException e) {  
  26.                   postResultIfNotInvoked(null);  
  27.               }  
  28.           }  
  29.       };  
  30.   }  
       原来callable就是mWorker,也就是说,FutureTask的run函数,会调用doInBackground函数。

AsyncTask.execute函数的执行过程

       1. AsyncTask.execute
[java] view plain copy
  1. public final AsyncTask<Params, Progress, Result> execute(Params... params) {  
  2.     return executeOnExecutor(sDefaultExecutor, params);  
  3. }  
       2.AsyncTask.executeOnExecutor
[java] view plain copy
  1. public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,  
  2.         Params... params) {  
  3.     if (mStatus != Status.PENDING) {  
  4.         switch (mStatus) {  
  5.             case RUNNING:  
  6.                 throw new IllegalStateException("Cannot execute task:"  
  7.                         + " the task is already running.");  
  8.             case FINISHED:  
  9.                 throw new IllegalStateException("Cannot execute task:"  
  10.                         + " the task has already been executed "  
  11.                         + "(a task can be executed only once)");  
  12.         }  
  13.     }  
  14.   
  15.     mStatus = Status.RUNNING;  
  16.   
  17.     onPreExecute();//调用onPreExecute  
  18.   
  19.     mWorker.mParams = params;//保存参数  
  20.     exec.execute(mFuture);//执行task  
  21.   
  22.     return this;  
  23. }  
        跳过SERIAL_EXECUTOR和THREAD_POOL_EXECUTOR的实现不谈,我们可以用如下的方式,简单理解exe.execute函数:
[java] view plain copy
  1. void execute(Runnable runnable){  
  2.     new Thread(runnable).start();  
  3. }  
        3. FutureTask.run()
[java] view plain copy
  1. public void run() {  
  2.      if (state != NEW ||  
  3.          !UNSAFE.compareAndSwapObject(this, runnerOffset,  
  4.                                       null, Thread.currentThread()))  
  5.          return;  
  6.      try {  
  7.          Callable<V> c = callable;  
  8.          if (c != null && state == NEW) {  
  9.              V result;  
  10.              boolean ran;  
  11.              try {  
  12.                  result = c.call();  
  13.                  ran = true;  
  14.              } catch (Throwable ex) {  
  15.                  result = null;  
  16.                  ran = false;  
  17.                  setException(ex);  
  18.              }  
  19.              if (ran)  
  20.                  set(result);  
  21.          }  
  22.      } finally {  
  23.          // runner must be non-null until state is settled to  
  24.          // prevent concurrent calls to run()  
  25.          runner = null;  
  26.          // state must be re-read after nulling runner to prevent  
  27.          // leaked interrupts  
  28.          int s = state;  
  29.          if (s >= INTERRUPTING)  
  30.              handlePossibleCancellationInterrupt(s);  
  31.      }  
  32.  }  
         前面已经讲过,会调用mWorker.call().
         4. WorkerRunnable.call()
[java] view plain copy
  1. mWorker = new WorkerRunnable<Params, Result>() {  
  2.            public Result call() throws Exception {  
  3.                mTaskInvoked.set(true);  
  4.   
  5.                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  6.                //noinspection unchecked  
  7.                return postResult(doInBackground(mParams));  
  8.            }  
  9.        };  
          5. AsyncTask.postResult()
[java] view plain copy
  1. private Result postResult(Result result) {  
  2.     @SuppressWarnings("unchecked")  
  3.     Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,  
  4.             new AsyncTaskResult<Result>(this, result));  
  5.     message.sendToTarget();  
  6.     return result;  
  7. }  
         通过sHandler,去UI线程执行接下来的工作。
        6. sHandler.handleMessage
[java] view plain copy
  1. private static class InternalHandler extends Handler {  
  2.     @SuppressWarnings({"unchecked""RawUseOfParameterizedType"})  
  3.     @Override  
  4.     public void handleMessage(Message msg) {  
  5.         AsyncTaskResult result = (AsyncTaskResult) msg.obj;  
  6.         switch (msg.what) {  
  7.             case MESSAGE_POST_RESULT:  
  8.                 // There is only one result  
  9.                 result.mTask.finish(result.mData[0]);  
  10.                 break;  
  11.             case MESSAGE_POST_PROGRESS:  
  12.                 result.mTask.onProgressUpdate(result.mData);  
  13.                 break;  
  14.         }  
  15.     }  
  16. }  
        7. AsyncTask.finish
[java] view plain copy
  1. private void finish(Result result) {  
  2.     if (isCancelled()) {  
  3.         onCancelled(result);  
  4.     } else {  
  5.         onPostExecute(result);  
  6.     }  
  7.     mStatus = Status.FINISHED;  
  8. }  
        通常情况下(即尚未调用过cancel(boolean interrupt)),isCannelled()为false,接下来会执行onPostExecute。

总结

       从本质上来讲,AsyncTask即为Execute和Handler的组合。AsyncTask利用Executor在后台线程中执行doInBackgroud函数,并利用handler执行onPostExecute函数。

       而AsyncTask的行为则由executeOnExecutor函数中参数exec决定。AsyncTask提供的SERIAL_EXECUTOR限定任务逐个执行,而THREAD_POOL_EXECUTOR支持最多128个任务并行执行,但是当待处理任务过多时,会抛出RejectedExecutionException。