Android 線程池的類型、區別以及爲什麼要用線程池

每一個 Android 應用進程在建立時,會同時建立一個線程,咱們稱之爲主線程,負責更新 UI 界面以及和處理用戶之間的交互,所以,在 Android 中,咱們又稱之爲 UI 線程。一個進程中 UI 線程只有一個,爲了避免形成界面卡頓、提升用戶體驗,咱們勢必要將一些耗時操做交由子線程來執行。html

使用子線程的方式主要分兩種:java

  • 直接使用 ThreadRunnable 等建立子並使用線程linux

  • 使用線程池建立並使用子線程android

線程池是什麼多線程

線程池是指在初始化一個多線程應用程序過程當中建立一個線程集合,而後在須要執行新的任務時重用這些線程而不是新建立一個線程。線程池中線程的數量一般徹底取決於可用內存數量和應用程序的需求;每一個線程都有被分配一個任務,一旦任務完成了,線程回到池子中並等待下一次分配任務。異步

通常狀況下,推薦使用線程池來建立和使用子線程,不建議使用第一種方式。函數

爲什麼要用線程池

上面說了,在 Android 開發過程當中,建議使用線程池來建立和使用子線程,那麼使用線程池的好處有哪些呢?性能

  • 線程池改進了一個應用程序的響應時間。因爲線程池中的線程已經準備好且等待被分配任務,應用程序能夠直接拿來使用而不用新建一個線程。優化

  • 線程池節省了 CLR 爲每一個短生存週期任務建立一個完整的線程開銷並能夠在任務完成後回收資源。google

  • 線程池根據當前在系統中運行的進程來優化線程片。

  • 線程池容許咱們開啓多個任務而不用爲每一個線程設置屬性。

  • 線程池容許咱們爲正在執行的任務的程序參數傳遞一個包含狀態信息的對象引用。

  • 線程池能夠用來解決處理一個特定請求最大線程數量限制問題。

  • 系統分配給每一個應用的線程棧是固定的,使用線程池能夠有效地避免線程棧溢出引發的應用崩潰。

Android 中的線程池

Android 中線程池的真正實現是 ThreadPoolExecutor,其構造方法有 5 個,經過一系列參數來配置線程池。下面介紹一個比較經常使用的構造方法及其參數的含義。

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory)
參數 含義
corePoolSize int: 線程池的核心線程數,默認狀況下,核心線程回一直在線程池中存活,即便他們處於閒置狀態。若是將 allowCoreThreadTimeOut 的屬性設置爲 true,那麼閒置的核心線程在等待新任務到來時會有超時策略,這個時間間隔由 keepAliveTime 所指定,當等待時間超過 keepAliveTime 所指定的時長後,核心線程就會被終止。
maximumPoolSize int: 線程池中容許的線程最大數量,當活動線程達到這個數值後,後續的新任務會被阻塞。
keepAliveTime long: 非核心線程閒置時的超時時長,超過這個時長,非核心線程就會被回收。當 allowCoreThreadTimeOut 屬性被設置爲 true 時,該參數一樣會做用於核心線程。
unit TimeUnit: keepAliveTime 參數的時間單位 ,參數爲 TimeUnit 的枚舉,常見的有 TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECOND(秒) 等。
workQueue BlockingQueue: 線程池中的任務隊列,經過線程池的 execute 方法提交的 Runnable 對象會存儲在這個參數中。
threadFactory ThreadFactory: 建立線程的線程工廠。ThreadFactory 是一個接口,只有一個方法:Thread newThread (Runnable r)
Throws  
IllegalArgumentException 符合如下任一條件,則拋出此異常: corePoolSize < 0 keepAliveTime < 0 maximumPoolSize <= 0 maximumPoolSize < corePoolSize
NullPointerException workQueue 或者 threadFactory 爲 null 時,拋出此異常。

ThreadPoolExecutor 執行任務時大體遵循以下規則:

  1. 若是線程池中的線程數量未達到核心線程的數量,那麼會直接啓動一個核心線程來執行任務。

  2. 若是線程池中的線程數量已經達到或超過核心線程的數量,那麼任務會被插入到任務隊列中等待執行。

  3. 若是步驟 2 中沒法將任務插入到任務隊列,則表示任務隊列已滿。此時,若是線程數量未達到 maximumPoolSize 值,則會當即啓動一個非核心線程來執行任務。

  4. 若是步驟 3 中線程數量大於或等於 maximumPoolSize 值,則拒絕執行次任務,此時 ThreadPoolExecutor 會調用 RejectedExecutionHandlerrejectedExecution 來通知調用者。

RejectedExecutionHandler 是線程池持有的一個對象,用於不能由 ThreadPoolExecutor 執行的任務的處理

Android 中線程池的類型及區別

Android 中最多見線程池有四種,分別是:FixedThreadPool、CacheThreadPool、ScheduledThreadPool 以及 SingleThreadPool,它們都直接或間接的經過配置 ThreadPoolExecutor 來實現本身的功能特性。

1. FixedThreadPool

線程數量固定的線程池,經過 ExecutorsnewFixedThreadPool 方法建立。有兩個重載的建立方法:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>(),
                                  threadFactory);
}

除非線程池被關閉,不然線程不會被回收,即時線程處於空閒狀態。若是在全部線程都處於活動狀態時提交額外的任務,它們將在隊列中等待,直到有一個線程可用爲止。由建立方法可知,FixedThreadPool 只有核心線程而且這個核心線程沒有超時機制(keepAliveTime 參數爲 0L),加上線程不會被回收,所以使用此類線程池能夠快速地響應外界的請求。

2. CacheThreadPool

線程數量不定的線程池,經過 ExecutorsnewCachedThreadPool 方法建立。有兩個重載的建立方法:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(/* corePoolSize*/ 0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(/* corePoolSize*/ 0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>(),
                                  threadFactory);
}

CacheThreadPool 有如下個特徵:

  • 沒有核心線程( corePoolSize 參數爲 0 ),只有非核心線程且非核心線程的數量爲 Integer.MAX_VALUE,這就至關於非核心線程的數量能夠無限大。

  • 線程池的線程處於空閒狀態時,線程池會重用空閒的線程來處理新任務,不然建立新的線程來處理,新建立的線程會添加到線程池中。這將提升執行許多短時間異步任務的程序性能。

  • 閒置時間超過 60 秒的空閒線程會被回收(keepAliveTime 參數爲 60L )。所以,閒置時間足夠長的 CacheThreadPool 也不會消耗任何系統資源。

3. ScheduledThreadPool

核心線程數量固定,非核心線程數量不定的線程池,經過 Executorsnewscheduledthreadpool 方法建立。有兩個重載的建立方法:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
        int corePoolSize, ThreadFactory threadFactory) {
    return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}

ScheduledThreadPool 相比較其餘三種線程池,有特殊性,由 ScheduledThreadPoolExecutor 實現, newscheduledthreadpool 方法也是經過建立 ScheduledThreadPoolExecutor 的實例來完成線程池的建立,代碼以下:

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue(), threadFactory);
}

ScheduledThreadPoolExecutor 的構造函數可知, ScheduledThreadPool 的核心線程數量是固定的,由傳入的 corePoolSize 參數決定,非核心線程數量能夠無限大。非核心線程閒置回收的超時時間爲 10秒DEFAULT_KEEPALIVE_MILLIS 的值爲 10L )。這類線程主要用於執行定時任務或者具備週期性的重複任務。

4. SingleThreadPool

只有一個核心線程,經過 Executorsnewsinglethreadexecutor 方法建立。有兩個重載的建立方法:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(/* corePoolSize*/ 1, /* maximumPoolSize*/ 1,
                                /* keepAliveTime*/ 0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(/* corePoolSize*/ 1, /* maximumPoolSize*/ 1,
                                /* keepAliveTime*/ 0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}

SingleThreadPool 由 代理類 FinalizableDelegatedExecutorService 建立。該線程池只有一個線程(核心線程),而且該線程池的任務隊列是無上限的,這就確保了全部的任務都在同一個線程中順序執行。

注意,若是因爲在執行期間出現故障而致使該線程終止,那麼若是須要執行後續任務,則新線程將取而代之。

四類線程池的區別

上面分別對 Android 中常見的 4 種線程池進行了簡單的介紹,除了這 4 種系統提供的線程池外,咱們在使用的過程當中,也能夠根據須要直接經過 ThreadPoolExecutor 的構造函數來靈活的配置線程池。那麼,上述的 4 種線程池,其區別在哪呢?瞭解其區別有助於咱們去選擇更爲合適的線程池或者直接經過 ThreadPoolExecutor 來配置更靈活的線程池。

FixedThreadPool 線程固定,且不會被回收,可以更快的響應外界請求

CachedThreadPool 只有非核心線程,且線程數至關於無限大,任何任務都會被當即執行。比較適合執行大量的耗時較少的任務。

ScheduledThreadPool 主要用於執行定時任務或者具備週期性的重複任務

SingleThreadPool 只有一個核心線程,確保全部任務都在同一線程中按順序完成。所以不須要處理線程同步的問題

 

參考

相關文章
相關標籤/搜索