天天看點

Android ThreadPoolExecutor線程池

引言

Android的線程池概念來自于Java的Executor,真正的線程池實作為ThreadPoolExecutor。在Android中,提供了4類不同的線程池,具體下面會說到。為什麼使用線程池呢?而不是使用Thread建立線程呢?因為使用線程池有以下幾個優點:

  • 重用線程池的線程,避免因為線程的建立和銷毀所帶來的性能開銷
  • 能有效控制線程池的最大并發數,避免線程之間搶占資源導緻阻塞
  • 能夠對線程進行簡單的管理,并提供定時執行以及指定間隔循環執行等功能

是以需要多次建立Thread時使用線程池較好。

ThreadPoolExecutor

它是線程池的真正實作,構造函數提供一系列的參數配置線程池。

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
           
  • corePoolSize:核心線程數,預設情況下,即時處于閑置狀态下,核心線程會線上程一直存活;如果設定allowCoreThreadTimeOut為true,閑置的核心線程等待任務期間會有逾時政策,時間間隔由keepAliveTime設定,最大為CPU核心數+1
  • maximumPoolSize:線程池容納最大線程數,當活動線程數超過這個數值,後續的新任務會導緻阻塞,最大為CPU核心數2倍+1
  • keepAliveTime:非核心線程閑置時逾時的時長,如果設定allowCoreThreadTimeOut為true,即作用于閑置的核心線程
  • unit:時間機關,使用TimeUnit枚舉
  • workQueue:線程池中的任務隊列,通過線程池execute方法送出Runnable對象會存儲這個參數中,容量為128
  • threadFactory:線程工廠,為線程池提供建立新線程的功能
  • handler:線程池對拒絕任務的處理政策。一般是隊列已滿或者無法成功執行任務,這時ThreadPoolExecutor會調用handler的rejectedExecution方法來通知調用者,有四個政策:
    • ThreadPoolExecutor.AbortPolicy() 直接抛出異常RejectedExecutionException
    • ThreadPoolExecutor.CallerRunsPolicy() 直接調用run方法并且阻塞執行
    • ThreadPoolExecutor.DiscardPolicy() 直接丢棄後來的任務
    • ThreadPoolExecutor.DiscardOldestPolicy() 丢棄在隊列中隊首的任務

執行任務規則可用currentSize表示線程池中目前線程數量,将上述過程可以表示如下

  • 當currentSize < corePoolSize時,直接啟動一個核心線程并執行任務
  • 當currentSize>=corePoolSize、并且workQueue未滿時,添加進來的任務會被安排到workQueue中等待執行
  • 當workQueue已滿,但是currentSize<maximumPoolSize時,會立即開啟一個非核心線程來執行任務
  • 當currentSize>=corePoolSize、workQueue已滿、并且currentSize>maximumPoolSize時,調用handler預設抛出RejectExecutionExpection異常
  • 當currentSize >corePoolSize線程,空閑時間達到keepAliveTime時,關閉空閑線程
  • 當設定allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閑時間達到keepAliveTime也将關閉

    FixedThreadPool

    通過Executors的newFixedThreadPool方法建立,它是一種線程數量固定的線程池,當線程處于空閑狀态時,它們并不會被回收,除非線程池被關閉了。當所有的線程都處于活動狀态時,新任務都會處于等待狀态,直到有線程空閑出來。由于FixedThreadPool隻有核心線程并且這些核心線程不會被回收,這意味着它能夠更加快速地響應外界的請求。
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
           

CachedThreadPool

通過Executors的newCachedThreadPool方法建立,它是一種線程數量不定的線程池,它隻有非核心線程,并且最大線程數為Integer.MAX_VALUE,從CachedThreadPool的特性來看,這類線程池比較适合執行大量的耗時較少的任務,當整個線程池都處于閑置狀态時,線程池中的線程都會逾時而被停止,這個時候CachedThreadPool之中實際上是沒有任何線程的,它幾乎是不占用任何系統資源的。

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

ScheduledThreadPool

通過Executors的newScheduledThreadPool方法建立,它的核心線程是固定的,非核心線程數是沒有限制的,主要用于執行定時任務和具有固定周期的重複任務。

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

SingleThreadExecutor

通過Executors的newSingleThreadExecutor方法建立,它隻有一個核心線程,確定所有任務都在同一個線程中按順序執行,使得這些不需要處理線程同步問題。

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}