AsyncTask源碼分析

AsyncTask 異步任務,可以很方便的在應用中執行下載等可能阻塞UI Thread的任務,現在分析一下它的源碼。
首先列出AsyncTask的一些核心方法和域:
 
public abstract class AsyncTask<Params, Progress, Result> {
  private static final int CORE_POOL_SIZE = 5;        //核心線程數
  private static final int MAXIMUM_POOL_SIZE = 128;   //最大線程數
  private static final int KEEP_ALIVE = 1;            //超時時間,當線程數超過核心線程數時,超過這個時間的空線程就會被銷毀,直到線程數等於核心線程

  private static final BlockingQueue<Runnable> sPoolWorkQueue =
    new LinkedBlockingQueue<Runnable>(10);           //用於傳輸和保持提交的任務。可以使用此隊列與池大小進行交互

  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的時候,從線程池取出一個線程來運行你的代碼。
管理規則是這樣的,
• 如果運行的線程少於 corePoolSize,則 Executor 始終首選添加新的線程,而不進行排隊。
• 如果運行的線程等於或多於 corePoolSize,則 Executor 始終首選將請求加入隊列,而不添加新的線程。
• 如果無法將請求加入隊列,則創建新的線程,除非創建此線程超出 maximumPoolSize,在這種情況下,任務將被拒絕。 
SERIAL_EXECUTOR 是維護線程安全,將新建的任務一個一個的加入到ThreadPoolExecutor 中。
通過源碼解決的一些問題:
 
1. API中說AsyncTask隻能運行在UI Thread,是這樣麼?
不是的,因為在生成AsyncTask和全局的線程池時,並沒有對線程進行限制,隻要所在的線程存在Looper(也就是調用過Looper.prepare的線程)都可以構造AsyncTask,所以在Service,Receiver中都可以構造AsyncTask。
 
2. AsyncTask建立的任務,是被立即執行麼?
不是立即執行,根據上述的規則,當目前已經有五個任務執行的時候,此時線程數等於corePoolSize,那麼再構造的AsyncTask就會進入sPoolWorkQueue,直到sPoolWorkQueue滿為止,這些線程都是被阻塞的,必須要有核心線程執行完成,他們才會執行。
有趣的是,如果sPoolWorkQueue滿瞭,這時再進來任務,就是構造新線程,執行此任務(而不是隊列中的任務),所以你建立的AsyncTask不是按照構造的順序來執行的,很可能後構造的反而先執行瞭。
 
3. AsyncTask構造的最大數量?
默認狀態,在每個進程中,可以最夠同時構造138個,其中同時運行128個,10個在阻塞隊列之中,如果在構造就會拋出異常。
 
4. 如何對AsyncTask進行優化?
THREAD_POOL_EXECUTOR 是 public static final的,所以你可以訪問到這個線程池,從而動態的設定 核心線程數、最大線程數等。除非你有特殊的情況處理,否則是沒有必要進行修改的。

 

摘自 達小生

發佈留言