第11章 Android的線程和線程池

11.1 主線程和子線程

  1. Android中的主線程主要處理和界面相關(guān)的事情,而子線程則往往用于執(zhí)行耗時操作,如網(wǎng)絡(luò)/IO操作等。線程的創(chuàng)建和銷毀的開銷較大,所以如果一個進(jìn)程要頻繁地創(chuàng)建和銷毀線程的話,都會采用線程池的方式。
    1. AsyncTask封裝了線程池和Handler,它主要是為了方便開發(fā)者在子線程中更新UI。
    2. HandlerThread是一種具有消息循環(huán)的線程,在它的內(nèi)部可以使用Handler。
    3. IntentService是一個服務(wù),它內(nèi)部采用HandlerThread來執(zhí)行任務(wù),當(dāng)任務(wù)執(zhí)行完畢后就會自動退出。因為它是服務(wù)的緣故,所以和后臺線程相比,它比較不容易被系統(tǒng)殺死。

11.2 Android中的線程形態(tài)

11.2.1 AsyncTask

  1. AsyncTask是一個抽象泛型類,它提供了Params、Progress、Result三個泛型參數(shù),如果task確實不需要傳遞具體的參數(shù),那么都可以設(shè)置為Void。下面是它的四個核心方法,其中doInBackground不是在主線程執(zhí)行的。
    1. onPreExecute() 主線程執(zhí)行,異步任務(wù)執(zhí)行之前調(diào)用
    2. doInBackground(Params.. params) 線程池中運行,執(zhí)行異步任務(wù),可以使用publishProgress更新認(rèn)為進(jìn)度。此方法需要返回計算結(jié)果給onPostExecute()
    3. onProgressUpdate(Progress... values) 主線程執(zhí)行,publishProgress會調(diào)用onProgressUpdate
    4. onPostExecute(Result result)主線程運行,result是后臺任務(wù)doInBackgroud的返回值
    5. onCancelled() 當(dāng)異步任務(wù)被取消時會調(diào)用,此時不調(diào)用onPostExceute
  2. 一些限制:
    1. AsyncTask類必須在主線程中加載(4.1后無需考慮)
    2. AsyncTask對象必須在主線程創(chuàng)建
    3. execute必須在UI線程調(diào)用
    4. 不能直接調(diào)用那些回調(diào)
    5. 一個Async對象只能execute一次。
  3. AsyncTask的原理
    1. AsyncTask中有兩個線程池:
      1. SerialExecutor:用于任務(wù)的排隊,默認(rèn)是串行的線程池
      2. THREAD_POOL_EXECUTOR。用于真正執(zhí)行任務(wù)。
    2. AsyncTask中有一個Handler,即InternalHandler,用于將執(zhí)行環(huán)境從線程池切換到主線程。AsyncTask內(nèi)部就是通過InternalHandler來發(fā)送任務(wù)執(zhí)行的進(jìn)度以及執(zhí)行結(jié)束等消息。
    3. AsyncTask的排隊執(zhí)行過程:
      1. 系統(tǒng)先把參數(shù)Params封裝為FutureTask對象,它相當(dāng)于Runnable;
      2. 接著將FutureTask交給SerialExecutor的execute方法,它先把FutureTask插入到任務(wù)隊列tasks中
      3. 如果這個時候沒有正在活動的AsyncTask任務(wù),那么就會執(zhí)行下一個AsyncTask任務(wù),同時當(dāng)一個AsyncTask任務(wù)執(zhí)行完畢之后,AsyncTask會繼續(xù)執(zhí)行其他任務(wù)直到所有任務(wù)都被執(zhí)行為止?!袌?zhí)行

11.2.2 HandlerThread

  1. HandlerThread的run方法中有Looper,也就是說HandlerThread內(nèi)部創(chuàng)建了消息隊列,是一個無限循環(huán)
  2. HandlerThread的用途
    1. 用于串行異步通信。比如我將一個Handler與HandlerThread對應(yīng),那么我就可以將業(yè)務(wù)通過Handler.post交給HanderThread去做
    2. IntentService
  3. 當(dāng)明確不需要HandlerThread時,要通過quit()和quitsafely()來終止線程運行

11.2.3 IntentService

  1. IntentService是一個繼承自Service的抽象類,要使用它就要創(chuàng)建它的子類。
  2. IntentService適合執(zhí)行一些高優(yōu)先級的后臺任務(wù),這樣不容易被系統(tǒng)殺死。
  3. 每執(zhí)行一次后臺任務(wù),就必須啟動一次IntentService(startService)。
  4. IntentService的后臺任務(wù)業(yè)務(wù)代碼,僅需要在onHandlerIntent中處理即可。
  5. 若只存在一個后臺任務(wù),onHandlerIntent方法執(zhí)行完任務(wù)后,stopSelf會直接停止服務(wù);若存在多個后臺任務(wù),當(dāng)onHandlerIntent執(zhí)行完最后一個任務(wù)后,stopSelf才會停止任務(wù)?!狪ntentService在多任務(wù)的情況下,onDestroy只執(zhí)行一次
  6. IntentService的原理
    1. IntentService的onCreate方法中會創(chuàng)建HandlerThread,并使用HandlerThread的Looper來構(gòu)造一個Handler對象ServiceHandler,這樣通過ServiceHandler對象發(fā)送的消息最終都會在HandlerThread中執(zhí)行。
    2. IntentService會將任務(wù)請求的Intent封裝到Message中,通過ServiceHandler發(fā)送給HandlerThread的MessageQueue,在ServiceHandler的handleMessage方法中會調(diào)用IntentService的抽象方法onHandleIntent。因此,后臺任務(wù)的邏輯在onHandlerIntent中處理即可。

11.3 Android中的線程池

  1. 線程池的好處
    1. 重用線程,避免線程的創(chuàng)建和銷毀帶來的性能消耗
    2. 有效控制線程池的并發(fā),避免線程之間搶資源帶來的阻塞
    3. 線程管理,提供定時/循環(huán)間隔執(zhí)行等功能
  2. Executor是一個接口,真正的線程池的實現(xiàn)為ThreadPoolExecutor。ThreadPoolExecutor提供了很多參數(shù)來配置線程池,android的線程池都是通過Executors所提供的工廠方法來得到的。
  3. ThreadPoolExecutor的構(gòu)造參數(shù)
    1. corePoolSize:核心線程數(shù),默認(rèn)情況下,核心線程會在線程中一直存活;
    2. maximumPoolSize:最大線程數(shù),當(dāng)活動線程數(shù)達(dá)到這個數(shù)值后,后續(xù)的任務(wù)將會被阻塞RejectedExecutionHandler;
    3. keepAliveTime:非核心線程閑置時的超時時長,超過這個時長,閑置的非核心線程就會被回收;
    4. unit:用于指定keepAliveTime參數(shù)的時間單位,有TimeUnit.MILLISECONDS、TimeUnit.SECONDS、TimeUnit.MINUTES等;
    5. workQueue:任務(wù)隊列,通過線程池的execute方法提交的Runnable對象會存儲在這個參數(shù)中;
    6. threadFactory:線程工廠,為線程池提供創(chuàng)建新線程的功能。它是一個接口,它只有一個方法Thread newThread(Runnable r);
    7. RejectedExecutionHandler:當(dāng)線程池?zé)o法執(zhí)行新任務(wù)時,可能是由于任務(wù)隊列已滿或者是無法成功執(zhí)行任務(wù),這個時候就會調(diào)用這個Handler的rejectedExecution方法來通知調(diào)用者,默認(rèn)情況下,rejectedExecution會直接拋出一個rejectedExecutionException。
  4. ThreadPoolExecutor執(zhí)行任務(wù)的規(guī)則:
    1. 如果線程池中的線程數(shù)未達(dá)到核心線程的數(shù)量,那么會直接啟動一個核心線程來執(zhí)行任務(wù);
    2. 如果線程池中的線程數(shù)量已經(jīng)達(dá)到或者超過核心線程的數(shù)量,那么任務(wù)會被插入到任務(wù)隊列中排隊等待執(zhí)行;
    3. 如果在步驟2中無法將任務(wù)插入到的任務(wù)隊列中,可能是任務(wù)隊列已滿,這個時候如果線程數(shù)量沒有達(dá)到規(guī)定的最大值,那么會立刻啟動非核心線程來執(zhí)行這個任務(wù);
      4.如果步驟3中線程數(shù)量已經(jīng)達(dá)到線程池規(guī)定的最大值,那么就拒絕執(zhí)行此任務(wù),ThreadPoolExecutor會調(diào)用RejectedExecutionHandler的rejectedExecution方法來通知調(diào)用者。
  5. Android中的4類ThreadPoolExecutor
    1. FixedThreadPool:線程數(shù)量固定的線程池,它只有核心線程,maximumPoolSize無限制
    2. CachedThreadPool:線程數(shù)量不固定的線程池,它只有非核心線程,maximumPoolSize無限制,keepAliveTime 60s
    3. ScheduledThreadPool:核心線程數(shù)量固定,maximumPoolSize無限制,主要用于執(zhí)行定時任務(wù)和具有固定周期的任務(wù),可以替代Timer;
    4. SingleThreadPool:只有一個核心線程的線程池,確保了所有的任務(wù)都在同一個線程中按順序執(zhí)行。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容