1. onPreExecute是否一定在UI線程執(zhí)行?
答: 不一定释漆。onPreExecute是調(diào)用execute()的線程執(zhí)行, 是在任務(wù)真正被插入到工作隊(duì)列之前執(zhí)行。早期的android要求execute()方法:必須在UI線程執(zhí)行够傍,因此onPreExceute會(huì)在UI線程執(zhí)行。較新的android版本挠铲,不再要求execute()在ui線程執(zhí)行冕屯,因此onPreExceute是在調(diào)用execute的線程執(zhí)行。
2. onPostExecute/onProgressUpdate是否在UI線程執(zhí)行?
答: 是的拂苹,這兩個(gè)方法都是通過Handler執(zhí)行安聘,運(yùn)行在UI線程中?
3. AsyncTask默認(rèn)是并行執(zhí)行還是串行的? 為什么要這樣?
答: 3.0之前默認(rèn)是串行,3.0~4.0默認(rèn)是并行浴韭,4.0之后默認(rèn)是串行带迟。
之所以改并行,當(dāng)然是為了效率考慮囱桨,利用線程池仓犬,提高并發(fā)性,但之后考慮到多線程可能存在一些線程安全問題舍肠,又改回串行了搀继。注意: AsyncTask本身只是一個(gè)線程池的封裝,既然是多線程翠语,必然存在線程安全問題叽躯,而這個(gè)問題需要程序員自身去保證,只要確保程序的線程安全性肌括,使用AysncTask并發(fā)模式是沒有任何問題的点骑。
4. AsyncTask線程池有多少個(gè)core線程,以及最大線程數(shù)?
答: coreSize = Math.max(2, Math.min(4, cpuCount - 1)), 也就是最少兩個(gè)谍夭,最多四個(gè)黑滴,具體多少跟cpu核心數(shù)相關(guān),考慮到目前主流機(jī)器都是4核以上紧索,coreSize也基本是四個(gè)袁辈。maximumSize = cpuCount * 2 + 1。由于默認(rèn)的并行隊(duì)列設(shè)置了allowCoreThreadTimeout珠漂,但空閑太久時(shí)晚缩,core thread也會(huì)被回收。
5. 任務(wù)隊(duì)列最大等待數(shù)是多少媳危?超出之后會(huì)怎樣? 如何避免問題
答:默認(rèn)的任務(wù)隊(duì)列容量是128, 若隊(duì)列已滿荞彼,再往隊(duì)列添加任務(wù),就會(huì)拋出RejectedExecutionException(這是java線程池默認(rèn)處理方式).
由于AsyncTask并沒有提供設(shè)置線程池RejectedExecutionHandler的方法待笑,因此鸣皂,想要避免這個(gè)異常,只能自己創(chuàng)建線程池, 并通過setDefaultExcutor方法為AsyncTask設(shè)置默認(rèn)線程池滋觉。
6. AsyncTask線程池的優(yōu)先級(jí)是什么?
答: 優(yōu)先級(jí)是THREAD_PRIORITY_BACKGROUND.
7. 如何獲取執(zhí)行結(jié)果?
答: 創(chuàng)建AsyncTask時(shí)签夭,其內(nèi)部會(huì)創(chuàng)建一個(gè)FutureTask, 改FutureTask封裝了doInBackground操作,執(zhí)行時(shí)就是將該FutureTask傳遞給線程池椎侠,因此獲取執(zhí)行結(jié)果就是通過FutureTask.get()方法獲取第租,AsyncTask提供了get()方法,封裝FutureTask.get(), 用于獲取結(jié)果我纪。
8. 如何取消一個(gè)任務(wù)慎宾,哪些任務(wù)是可以取消的?
答: 前面講到AsyncTask只是一個(gè)基于線程池和FutureTask的封裝丐吓,哪些任務(wù)可以取消也完全是線程池與FutureTask的邏輯,AsyncTask的cancel方法僅僅調(diào)用FutureTask的cancel趟据。因此哪些任務(wù)可取消券犁,就看FutureTask是否可取消⌒诩睿考慮調(diào)用cancel時(shí)粘衬,F(xiàn)utureTask的狀態(tài):
- 未開始執(zhí)行(New狀態(tài)): 這種情況下會(huì)將狀態(tài)置為(Interrupting或cancelled, 后續(xù)當(dāng)此FutureTask的run方法執(zhí)行時(shí),發(fā)現(xiàn)其狀態(tài)不是new, 會(huì)跳過執(zhí)行.
- 正在執(zhí)行(runner線程不等于null): 此時(shí)會(huì)根據(jù)參數(shù)mayInterruptIfRunning決定是否調(diào)用runner線程的interrupt方法咳促,注意: interrupt并不是中斷線程的意思稚新,只有當(dāng)線程處于wait(), sleep(), join()等方法上阻塞時(shí),這些方法會(huì)立即返回跪腹,且拋出InterruptionException褂删。若當(dāng)時(shí)線程正處于running狀態(tài)時(shí),interrupt方法僅僅設(shè)置線程為interrupted狀態(tài)冲茸,而不會(huì)中斷線程的執(zhí)行屯阀。
- 已執(zhí)行: 這種情況不會(huì)發(fā)生任何事情。
可以看出轴术,能cancel的主要是尚未開始執(zhí)行的任務(wù)难衰。cancel正在執(zhí)行的任務(wù),具有不可預(yù)知性膳音。并且很重要一點(diǎn)召衔,cancel并沒有將FutureTask從線程池的等待隊(duì)列移除,任然占據(jù)128中的一個(gè)位置祭陷。
9. 如何將一個(gè)Runnable交給AsyncTask框架執(zhí)行?
答: 這種情況主要是想把任務(wù)交個(gè)線程池執(zhí)行,而又沒有必要自己創(chuàng)建線程或線程池趣席,而借用AsyncTask的線程池完成兵志。通過AsyncTask的靜態(tài)方法execute(Runnable)完成。這種任務(wù)既不能獲取結(jié)果宣肚,也不能取消想罕。