AsyncTask作為一個優秀的封裝,很多人都在用,可是我估計很多人并不清楚多個AsyncTask對象到底是串行執行的,還是并行執行的,如果是并行的,那么最多同時執行幾個異步任務呢?
源碼面前無秘密,我們看一下源代碼就知道了。
這里以Android-23為例。
AyncTask調用例子
[html]view plaincopy
AsyncTasktask=newAsyncTask()?{
@Override
protected?Object?doInBackground(Object[]?params)?{
return?null;
}
};
task.execute();
普通AsyncTask對象調用如上,主要是通過task.execute()來執行異步任務。那么execute到底做了什么呢?
AsyncTask的execute函數
看看實現:
[html]view plaincopy
@MainThread
public?final?AsyncTaskexecute(Params...?params)?{
return?executeOnExecutor(sDefaultExecutor,?params);
}
超簡單,就一行。先看看executeOnExecutor函數:
[html]view plaincopy
@MainThread
public?final?AsyncTaskexecuteOnExecutor(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;
}
主要看exec.execute(mFuture)這一行。
exec是什么呢?從execute函數里面的實現就可以看到,exec是sDefaultExecutor,那么sDefaultExecutor是什么玩意呢?
從一下代碼可以清楚的看到:
[html]view plaincopy
public?static?final?ExecutorSERIAL_EXECUTOR=newSerialExecutor();
private?static?final?intMESSAGE_POST_RESULT=0x1;
private?static?final?intMESSAGE_POST_PROGRESS=0x2;
private?static?volatile?ExecutorsDefaultExecutor=SERIAL_EXECUTOR;
sDefaultExecutor是SerialExecutor的一個實例,而且它是個靜態變量。也就是說,一個進程里面所有AsyncTask對象都共享同一個SerialExecutor對象。
那么所有的秘密就在于SerialExecutor的execute函數了。
SerialExecutor的execute函數
直接貼出SerialExecutor的實現:
[html]view plaincopy
private?static?class?SerialExecutor?implements?Executor?{
final?ArrayDequemTasks=newArrayDeque();
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
[html]view plaincopy
public?static?final?ExecutorTHREAD_POOL_EXECUTOR
=newThreadPoolExecutor(CORE_POOL_SIZE,?MAXIMUM_POOL_SIZE,?KEEP_ALIVE,
TimeUnit.SECONDS,?sPoolWorkQueue,?sThreadFactory);
如果我們直接使用THREAD_POOL_EXECUTOR會怎么樣呢?
看下圖:
這次的執行順序跟上次不一樣了。可以看出好像3個任務并行執行了。不像之前的排隊執行。
關于THREAD_POOL_EXECUTOR,有興趣可以看進去,大致的意思就是,
[html]view plaincopy
private?static?final?intCPU_COUNT=Runtime.getRuntime().availableProcessors();
private?static?final?intCORE_POOL_SIZE=CPU_COUNT+?1;
private?static?final?intMAXIMUM_POOL_SIZE=CPU_COUNT*?2?+?1;
這是個線程池,有兩個概念,一個是線程池里面核心線程數,一個是最大線程數。從上面的定義可以大概看出來,核心線程數是CPU個數+1,最大是CPU個數 * 2 + 1.
至于怎么調度執行,那就有一套算法了,這里就不介紹了。但是有一點可以肯定,它不是排隊在一個線程里面執行的,所以也就看到了上面的結果。
實際上,我們也可以自己實現?一個執行器,如:
[html]view plaincopy
public?class?MyThreadPoolExecutor?extends?AbstractExecutorService
然后調用AsyncTask的executeOnExecutor,把自己的MyThreadPoolExecutor對象傳進去,達到自己想要的效果。
不過,還是推薦使用系統默認的,也就是排隊執行的方式,除非有特殊需求,我們才搞特殊化處理。
原文地址:http://blog.csdn.net/zj510/article/details/51622597