Asynctask踩坑

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容