AsyncTask 異步任務,可以很方便的在應用中執(zhí)行下載等可能阻塞UI Thread的任務,,現(xiàn)在分析一下它的源碼,。
首先列出AsyncTask的一些核心方法和域:
public abstract class AsyncTask<Params, Progress, Result> {
private static final int CORE_POOL_SIZE = 5; //核心線程數(shù)
private static final int MAXIMUM_POOL_SIZE = 128; //最大線程數(shù)
private static final int KEEP_ALIVE = 1; //超時時間,當線程數(shù)超過核心線程數(shù)時,,超過這個時間的空線程就會被銷毀,,直到線程數(shù)等于核心線程
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10); //用于傳輸和保持提交的任務??梢允褂么岁犃信c池大小進行交互
public static final Executor THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
}
其實AsyncTask的的核心就是一個ThreadPoolExecutor ,,這是一個Java的線程池,在生成AsyncTask的時候,,從線程池取出一個線程來運行你的代碼,。
管理規(guī)則是這樣的,
如果運行的線程少于 corePoolSize,,則 Executor 始終首選添加新的線程,,而不進行排隊。
如果運行的線程等于或多于 corePoolSize,,則 Executor 始終首選將請求加入隊列,,而不添加新的線程。
如果無法將請求加入隊列,,則創(chuàng)建新的線程,,除非創(chuàng)建此線程超出 maximumPoolSize,在這種情況下,,任務將被拒絕,。
SERIAL_EXECUTOR 是維護線程安全,將新建的任務一個一個的加入到ThreadPoolExecutor 中,。
通過源碼解決的一些問題:
1. API中說AsyncTask只能運行在UI Thread,,是這樣么?
不是的,,因為在生成AsyncTask和全局的線程池時,,并沒有對線程進行限制,只要所在的線程存在Looper(也就是調(diào)用過Looper.prepare的線程)都可以構造AsyncTask,所以在Service,,Receiver中都可以構造AsyncTask,。
2. AsyncTask建立的任務,是被立即執(zhí)行么?
不是立即執(zhí)行,,根據(jù)上述的規(guī)則,,當目前已經(jīng)有五個任務執(zhí)行的時候,此時線程數(shù)等于corePoolSize,,那么再構造的AsyncTask就會進入
sPoolWorkQueue,,直到sPoolWorkQueue滿為止,這些線程都是被阻塞的,,必須要有核心線程執(zhí)行完成,,他們才會執(zhí)行。
有趣的是,,如果sPoolWorkQueue滿了,,這時再進來任務,就是構造新線程,,執(zhí)行此任務(而不是隊列中的任務),,所以你建立的AsyncTask不是按照構造的順序來執(zhí)行的,很可能后構造的反而先執(zhí)行了,。
3. AsyncTask構造的最大數(shù)量,?
默認狀態(tài),在每個進程中,,可以最夠同時構造138個,,其中同時運行128個,10個在阻塞隊列之中,,如果在構造就會拋出異常,。
4. 如何對AsyncTask進行優(yōu)化?
THREAD_POOL_EXECUTOR 是 public static final的,所以你可以訪問到這個線程池,,從而動態(tài)的設定 核心線程數(shù),、最大線程數(shù)等。除非你有特殊的情況處理,,否則是沒有必要進行修改的,。
摘自 達小生