多個AsyncTask執行順序:並行or序列
阿新 • • 發佈:2019-02-07
AsyncTask作為一個優秀的封裝,很多人都在用,可是我估計很多人並不清楚多個AsyncTask物件到底是序列執行的,還是並行執行的,如果是並行的,那麼最多同時執行幾個非同步任務呢?
原始碼面前無祕密,我們看一下原始碼就知道了。
這裡以Android-23為例。
AyncTask呼叫例子
超簡單,就一行。先看看executeOnExecutor函式:
sDefaultExecutor是SerialExecutor的一個例項,而且它是個靜態變數。也就是說,一個程序裡面所有AsyncTask物件都共享同一個SerialExecutor物件。 那麼所有的祕密就在於SerialExecutor的execute函數了。 SerialExecutor的execute函式 直接貼出SerialExecutor的實現:
程式碼本身很簡單,從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
- AsyncTask task = new AsyncTask() {
- @Override
- protected Object doInBackground(Object[] params) {
- return null;
- }
- };
- task.execute();
- @MainThread
-
public final AsyncTask<
- return executeOnExecutor(sDefaultExecutor, params);
- }
超簡單,就一行。先看看executeOnExecutor函式:
- @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;
- }
- 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;
sDefaultExecutor是SerialExecutor的一個例項,而且它是個靜態變數。也就是說,一個程序裡面所有AsyncTask物件都共享同一個SerialExecutor物件。 那麼所有的祕密就在於SerialExecutor的execute函數了。 SerialExecutor的execute函式 直接貼出SerialExecutor的實現:
- 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);
- }
- }
- }
程式碼本身很簡單,從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
- public static final Executor THREAD_POOL_EXECUTOR
- = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
- TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
- 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;
- public class MyThreadPoolExecutor extends AbstractExecutorService