詳解一說明了線程池的基本配置參數(shù),這里繼續(xù)說AsyncTask內(nèi)部是怎樣對線程池進(jìn)行配置使用的
AsyncTask對線程池的配置
以API 23(6.0)為例哆档,看一看AsyncTask里面的線程池是以什么參數(shù)構(gòu)造的;AsyncTask里面有“兩個”線程池舌狗;一個THREAD_POOL_EXECUTOR
一個SERIAL_EXECUTOR
垃你;之所以打引號,是因?yàn)槠鋵?shí)SERIAL_EXECUTOR
也使用THREAD_POOL_EXECUTOR
實(shí)現(xiàn)的冒晰,只不過加了一個隊列弄成了串行而已,那么這個THREAD_POOL_EXECUTOR
是如何構(gòu)造的呢竟块?
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到壶运,AsyncTask里面線程池是一個核心線程數(shù)為CPU + 1
,最大線程數(shù)為CPU * 2 + 1
彩郊,工作隊列長度為128的線程池前弯;并且沒有傳遞handler
參數(shù),那么使用的就是默認(rèn)的Handler(拒絕執(zhí)行).
AsyncTask使用線程池易導(dǎo)致的問題
從AsyncTask對線程池的使用秫逝,可以看到容易出現(xiàn)以下問題:
- 如果任務(wù)過多恕出,那么超過了工作隊列以及線程數(shù)目的限制導(dǎo)致這個線程池發(fā)生阻塞,那么悲劇發(fā)生违帆,默認(rèn)的處理方式會直接拋出一個異常導(dǎo)致進(jìn)程掛掉浙巫。假設(shè)你自己寫一個異步圖片加載的框架,然后用AsyncTask實(shí)現(xiàn)的話刷后,當(dāng)你快速滑動ListView的時候很容易發(fā)生這種異常的畴;這也是為什么各大ImageLoader都是自己寫線程池和Handlder的原因。
- 這個線程池是一個靜態(tài)變量(類變量)尝胆;那么在同一個進(jìn)程之內(nèi)丧裁,所有地方使用到的AsyncTask默認(rèn)構(gòu)造函數(shù)構(gòu)造出來的AsyncTask都使用的是同一個線程池,如果App模塊比較多并且不加控制的話含衔,很容易滿足第一條的崩潰條件煎娇;如果你不幸在不同的AsyncTask的doInBackgroud里面訪問了共享資源二庵,那么就會發(fā)生各種并發(fā)編程問題。
- 在AsyncTask全部執(zhí)行完畢之后缓呛,進(jìn)程中還是會常駐corePoolSize個線程催享;在Android 4.4 (API 19)以下,這個corePoolSize是hardcode的哟绊,數(shù)值是5因妙;API 19改成了
cpu + 1
;也就是說票髓,在Android 4.4以前攀涵;如果你執(zhí)行了超過五個AsyncTask;然后啥也不干了洽沟,進(jìn)程中還是會有5個AsyncTask線程