Android 線程池詳解

前言

做Android開發,有時會啓動大量的線程,如果不適當的管理,會增加系統的開銷,降低程序的性能。而線程池是Android性能優化的一個方案,有諸多好處:


 1. 可以重用線程池裏的線程,避免線程的創建和銷帶來的性能開銷。
 2. 可以控制線程池的最大併發數,避免大量線程之前搶佔系統資源而造成阻塞現象。
 3. 可以對線程進行管理,比如定時執行某線程或是循環執行等功能。

ThreadPoolExecutor

我們知道Java中有一個Executor這樣一個接口。而ExecutorService就是繼承了Executor的一個接口,真正實現的是ThreadPoolExecutor。先看下ThreadPoolExecutor的構造方法(比較常用的):

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

參數:

  • corePoolSize:核心線程。
  • maximumPoolSize:線程池所能容納的最大線程數。
  • keepAliveTime:非核心線程閒置的超時時長,如果超過這個值,非核心線程就會被回收。
  • unit:用於指定keepAliveTime的時間單位。
  • workQueue:線程池中的任務隊列。
  • threadFactory:爲線程池提供新建線程的功能。

    這些參數配置在AsyncTask中就有所體現:

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的代碼,我們可以看出:

  1. 核心線程=cpu核心數+1
  2. 核心線程沒有超時機制,非核心線程的閒置超時時間爲1秒
  3. 線程池的最大線程數爲cpu核心數*2+1
  4. 任務隊列的容量爲128

    ThreadPoolExecutor執行任務的時候,遵循以下規則:

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


Android中的線程池

Android中也通過配置ThreadPoolExecutor來實現了不同類型的線程池,下面我們來介紹最常用的4類線程池:

1.FixedThreadPool

通過調用Executes的newFixedThreadPool方法來創建:

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

我們發現,FixedThreadPool線程池具備以下特性:

  1. 線程數量固定,在創建的時候,指定數量。
  2. 當線程處於空閒狀態時,它們不會被回收,直到線程池被關閉。
  3. 當所有的線程都處於活動狀態,新任務會處於等待狀態,直到有線程空閒出來。
  4. 所有線程都是核心線程,且沒有超時機制,隊列也沒有大小限制

2.CachedThreadPool

通過調用Executes的newCachedThreadPool方法來創建:

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

我們發現,CachedThreadPool線程池具備以下特性:

  1. 線程數量不固定,並且最大數爲Integer.MAX_VALUE
  2. 當線程處於空閒狀態時,如果閒置60秒就會被回收
  3. 當所有的線程都處於活動狀態,新任務會創建新的線程執行,否則就使用閒置線程。
  4. 由此看來,CachedThreadPool線程池適合做大量的耗時較少的任務。

3.ScheduledThreadPool

通過調用Executes的newScheduledThreadPool方法來創建:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

我們發現,ScheduledThreadPool線程池具備以下特性:

  1. 核心線程是固定的,創建時指定
  2. 非核心線程是不固定的,閒置會被回收
  3. CachedThreadPool,主要用於執行定時任務和具有固定週期的重複任務

3.SingleThreadExecutor

通過調用Executes的newSingleThreadExecutor方法來創建:

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

我們發現,SingleThreadExecutor線程池具備以下特性:

  1. 內部只有一個核心線程
  2. 所有任務在線程中排隊執行
  3. 感覺作用就是不用擔心線程同步了,,
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章