1. 程式人生 > >多個AsyncTask執行順序:並行or序列

多個AsyncTask執行順序:並行or序列

AsyncTask作為一個優秀的封裝,很多人都在用,可是我估計很多人並不清楚多個AsyncTask物件到底是序列執行的,還是並行執行的,如果是並行的,那麼最多同時執行幾個非同步任務呢? 原始碼面前無祕密,我們看一下原始碼就知道了。 這裡以Android-23為例。 AyncTask呼叫例子
  1. AsyncTask task = new AsyncTask() {  
  2.      @Override  
  3.      protected Object doInBackground(Object[] params) {  
  4.          return null;  
  5.      }  
  6.  };  
  7.  task.execute();  
普通AsyncTask物件呼叫如上,主要是通過task.execute()來執行非同步任務。那麼execute到底做了什麼呢? AsyncTask的execute函式 看看實現:
  1. @MainThread  
  2. public final AsyncTask<
    Params, Progress, Result> execute(Params... params) {  
  3.     return executeOnExecutor(sDefaultExecutor, params);  
  4. }  

超簡單,就一行。先看看executeOnExecutor函式:
  1. @MainThread  
  2.  public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,  
  3.          Params... params) {  
  4.      if (mStatus != Status.PENDING) {  
  5.          switch (mStatus) {  
  6.              case RUNNING:  
  7.                  throw new IllegalStateException("Cannot execute task:"  
  8.                          + " the task is already running.");  
  9.              case FINISHED:  
  10.                  throw new IllegalStateException("Cannot execute task:"  
  11.                          + " the task has already been executed "  
  12.                          + "(a task can be executed only once)");  
  13.          }  
  14.      }  
  15.      mStatus = Status.RUNNING;  
  16.      onPreExecute();  
  17.      mWorker.mParams = params;  
  18.      exec.execute(mFuture);  
  19.      return this;  
  20.  }  
主要看exec.execute(mFuture)這一行。 exec是什麼呢?從execute函式裡面的實現就可以看到,exec是sDefaultExecutor,那麼sDefaultExecutor是什麼玩意呢? 從一下程式碼可以清楚的看到:
  1. public static final Executor SERIAL_EXECUTOR = new SerialExecutor();  
  2. private static final int MESSAGE_POST_RESULT = 0x1;  
  3. private static final int MESSAGE_POST_PROGRESS = 0x2;  
  4. private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;  

sDefaultExecutor是SerialExecutor的一個例項,而且它是個靜態變數。也就是說,一個程序裡面所有AsyncTask物件都共享同一個SerialExecutor物件。 那麼所有的祕密就在於SerialExecutor的execute函數了。 SerialExecutor的execute函式 直接貼出SerialExecutor的實現:
  1. private static class SerialExecutor implements Executor {  
  2.     final ArrayDeque<Runnable>mTasks = new ArrayDeque<Runnable>();  
  3.     Runnable mActive;  
  4.     public synchronized void execute(final Runnable r) {  
  5.         mTasks.offer(new Runnable() {  
  6.             public void run() {  
  7.                 try {  
  8.                     r.run();  
  9.                 } finally {  
  10.                     scheduleNext();  
  11.                 }  
  12.             }  
  13.         });  
  14.         if (mActive == null) {  
  15.             scheduleNext();  
  16.         }  
  17.     }  
  18.     protected synchronized void scheduleNext() {  
  19.         if ((mActive = mTasks.poll()) != null) {  
  20.             THREAD_POOL_EXECUTOR.execute(mActive);  
  21.         }  
  22.     }  
  23. }  

程式碼本身很簡單,從execute裡面就能看出,非同步任務r被放到了ArrayDeque物件mTasks中,然後通過scheduleNext()來從mTasks裡面得到一個任務去一個後臺執行緒執行。 在一個非同步任務執行後,再次呼叫scheduleNext來執行下一個任務(run函式)。 所以,很清楚,其實SerialExecutor是一個一個執行任務的,而所有的AsyncTask物件又共享同一個SerialExecutor物件(靜態成員)。 所以,我們可以肯定:至少在Android-23 SDK裡面,多個AsyncTask物件是序列執行的。 實際是不是呢,做個實驗就知道:
測試程式碼超簡單,就是建立3個AsyncTask物件,做了一樣的事情,就是在doInBackground裡面列印log。 我們從log可以清楚的看到,AsyncTask物件1,2,3是序列執行的。 這也證實了,Android-23 sdk裡面 多個AsyncTask物件確實是序列執行的。 如何並行執行多個AsyncTask物件 那麼有沒有辦法並行執行呢?肯定有了。 看AsyncTask的實現,裡面有個Executor
  1. public static final Executor THREAD_POOL_EXECUTOR
  2.          = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,  
  3.                  TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);  
如果我們直接使用THREAD_POOL_EXECUTOR會怎麼樣呢? 看下圖: 這次的執行順序跟上次不一樣了。可以看出好像3個任務並行執行了。不像之前的排隊執行。 關於THREAD_POOL_EXECUTOR,有興趣可以看進去,大致的意思就是,
  1. private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();  
  2. private static final int CORE_POOL_SIZE = CPU_COUNT + 1;  
  3. private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;  
這是個執行緒池,有兩個概念,一個是執行緒池裡面核心執行緒數,一個是最大執行緒數。從上面的定義可以大概看出來,核心執行緒數是CPU個數+1,最大是CPU個數 * 2 + 1. 至於怎麼排程執行,那就有一套演算法了,這裡就不介紹了。但是有一點可以肯定,它不是排隊在一個執行緒裡面執行的,所以也就看到了上面的結果。 實際上,我們也可以自己實現 一個執行器,如:
  1. public class MyThreadPoolExecutor extends AbstractExecutorService  
然後呼叫AsyncTask的executeOnExecutor,把自己的MyThreadPoolExecutor物件傳進去,達到自己想要的效果。 不過,還是推薦使用系統預設的,也就是排隊執行的方式,除非有特殊需求,我們才搞特殊化處理。 原文連結:http://blog.csdn.net/zj510/article/details/51622597