Android中的線程池簡介

Android中的線程池

線程池有以下三個優點:

(1)重用線程池中的線程,避免因爲線程的創建和銷燬所帶來的性能開銷。
(2)能有效控制線程的最大併發數,避免大量的線程之間的相互搶佔資源而導致的阻塞現象。
(3)能夠對線程進行簡單的管理,並提供定時執行以及指定間隔循環執行等功能。

Android中的線程池的概念來源於Java中的Executor。Executor是個接口,真正的線程池實現爲ThreadPoolExecutor。

ThreadPoolExecutor比較常用的構造:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime
                          TimeUnit unit,
                          BlockingQueue<Runnable>workQueue,
                          ThreadFactory threadFactory)

corePoolSize

核心線程數。默認情況下,核心線程會在線程中一直存活,即使他們處於閒置狀態。如果將ThreadPoolExecutor的allowCoreThreadTimeOut屬性設置爲true,那麼閒置的核心線程在等待新任務到來時會有超時策略,這個時間間隔由keepAliveTime所指定,當等待時間超過keepAliveTime所指定的時長後,核心線程就回被終止。

maximumPoolSize

線程池所能容納的最大線程數,當活動線程數達到這個數值後,後續的新任務將會被阻塞。

keepAliveTime

非核心線程閒置時的超時時長。超過這個時長,非核心線程就會被回收。當ThreadPoolExecutor的allowCoreThreadTimeOut屬性設置爲true時,keepAliveTime同樣會作用於核心線程。

unit

用於指定keepAliveTime參數的時間單位,這是一個枚舉,常用的有TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)以及TimeOut.MINUTES(分鐘)等。

workQueue

線程池中的任務隊列,通過線程池的恩行execute方法提交的Runnable對象會存儲在這個參數中。

threadFactory

線程工廠,爲線程池提供創建新線程的功能。ThreadFactory是一個接口,它只有一個方法:Thread newThread(Runnable r).

ThreadPoolExecutor執行任務時大致遵循如下規則:

(1)如果線程池中的線程數量未達到核心線程的數量,那麼會直接啓動一個核心線程來執行任務。
(2)如果線程池中的線程數量已經達到或者超過核心線程數量,那麼任務會被插入到任務隊列中排隊等待執行。
(3)如果在步驟(2)中無法將任務插入到任務隊列中,這往往是由於任務隊列已滿,這個時候如果線程數量未達到線程池規定的最大值,那麼會立刻啓動一個非核心線程來執行任務。
(4)如果步驟(3)中的線程數量以及達到線程池規定的最大值,那麼就拒絕執行此任務,ThreadPoolExecutor會調用RejectedExecutionHandler的rejectedExecution方法來通知調用者。

ThreadPoolExecutor的參數配置在AsnycTask中有明顯的提現:

public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    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 ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    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對THREAD_POOL_EXECUTOR這個線程池進行了如下規格配置:

  • 核心線程數等於CPU核心數+1;
  • 線程池的最大線程數爲cpu核心數的2倍+1;
  • 核心線程無超時機制,非核心線程在閒置時的超時時間爲1秒;
  • 任務隊列的容量爲128.

線程池的分類

1.FixedThreadPool

通過Executors的newFixedThreadPool方法來創建。它是一種線程數量固定的線程池,當線程處於空閒時,它們不會被回收,除非線程池被關閉了。當所有的線程都處於活動狀態時,新任務都會處於等待狀態,直到有線程空閒出來。由於FixedThreadPool只有核心線程並且這些核心線程不會被回收,這意味着它能夠更快的響應外界的請求。newFixedThreadPool方法的實現如下:

public class Executors {

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

    ...
}

2.CachedThreadPool

通過Executors的newCachedThreadPool方法來創建。它是一種線程數量不固定的線程池,它只有非核心線程,並且最大線程數爲Integer.MAX_VALUE。當線程池中的線程都處於活動狀態時,線程池會創建新的線程來處理新任務,否則就會利用空閒的線程來處理新任務。線程池中的空閒線程都有超時機制,超時時長是60秒。和FixedThreadPool不同的是,CachedThreadPool的任務隊列其實相當於一個空集合,這將導致任何任務都會立即執行,因爲在這種場景下SynchronousQueue是無法插入任務的。CachedThreadPool線程池比較適合執行大量的耗時較少的任務。當整個線程池處於閒置狀態時,線程池中的線程都會超時而被停止,這個時候CachedThreadPool之中實際上是沒有任何線程的,它幾乎不佔用系統資源。
newCachedThreadPool方法實現如下:

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

3.ScheduledThreadPool

通過Executors的newScheduledThreadPool方法來創建。它的核心線程數量是固定的,而非核心線程數時沒有限制的,並且當非核心線程閒置時會被立即回收。這類線程池主要用於執行定時任務和具有固定週期的重複任務,實現如下:

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

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
         new DelayedWorkQueue());
}

4.SingleThreadExecutor

通過Executors的newSingleThreadExecutor方法來創建。這類線程池內部只有一個核心線程,它確保所有的任務都在同一個線程中按順序執行。使得所有任務間不需要處理線程同步的問題。實現如下:

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章