Android開發——Android中常見的4種線程池(保證你能看懂並理解)


0.前言

轉載請注明出處:Android開發——Android中常見的4種線程池

使用線程池可以給我們帶來很多好處,首先通過線程池中線程的重用,減少創建和銷毀線程的性能開銷。其次,能控制線程池中的並發數,否則會因為大量的線程爭奪CPU資源造成阻塞。最后,線程池能夠對線程進行管理,比如使用ScheduledThreadPool來設置延遲N秒后執行任務,並且每隔M秒循環執行一次。

下面會通過介紹線程池中的真正實現者——ThreadPoolExecutor來引出Android中的4類線程池的使用以及特性分析,會加上筆者自己的理解,和自認為比較恰當的比喻,幫助理解。

1.凡事得靠ThreadPoolExecutor(鋪墊環節,懂的直接跳過)

Executor作為一個接口,它的具體實現就是ThreadPoolExecutor

Android中的線程池都是直接或間接通過配置ThreadPoolExecutor來實現不同特性的線程池。

先介紹ThreadPoolExecutor的一個常用的構造方法。

/*
*@ ThreadPoolExecutor構造參數介紹
*@author SEU_Calvin
* @date 2016/09/03
*/
public ThreadPoolExecutor(
//核心線程數,除非allowCoreThreadTimeOut被設置為true,否則它閑着也不會死
int corePoolSize, 
//最大線程數,活動線程數量超過它,后續任務就會排隊                   
int maximumPoolSize, 
//超時時長,作用於非核心線程(allowCoreThreadTimeOut被設置為true時也會同時作用於核心線程),閑置超時便被回收           
long keepAliveTime,                          
//枚舉類型,設置keepAliveTime的單位,有TimeUnit.MILLISECONDS(ms)、TimeUnit. SECONDS(s)等
TimeUnit unit,
//緩沖任務隊列,線程池的execute方法會將Runnable對象存儲起來
BlockingQueue<Runnable> workQueue,
//線程工廠接口,只有一個new Thread(Runnable r)方法,可為線程池創建新線程
ThreadFactory threadFactory)

ThreadPoolExecutor的各個參數所代表的特性注釋中已經寫的很清楚了,那么ThreadPoolExecutor執行任務時的心路歷程是什么樣的呢?(以下用currentSize表示線程池中當前線程數量)

  1. 當currentSize<corePoolSize時,沒什么好說的,直接啟動一個核心線程並執行任務。

  2. 當currentSize>=corePoolSize、並且workQueue未滿時,添加進來的任務會被安排到workQueue中等待執行。

  3. 當workQueue已滿,但是currentSize<maximumPoolSize時,會立即開啟一個非核心線程來執行任務。

  4. 當currentSize>=corePoolSize、workQueue已滿、並且currentSize>maximumPoolSize時,調用handler默認拋出RejectExecutionExpection異常。

2. Android中的四類線程池

Android中最常見的四類具有不同特性的線程池分別為FixThreadPool、CachedThreadPool、ScheduleThreadPool以及SingleThreadExecutor。

2.1 FixThreadPool(一堆人排隊上公廁)

/*
*@FixThreadPool介紹
*@author SEU_Calvin
* @date 2016/09/03
*/
public static ExecutorService newFixThreadPool(int nThreads){
    return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}
//使用
Executors.newFixThreadPool(5).execute(r);
  1. 從配置參數來看,FixThreadPool只有核心線程,並且數量固定的,也不會被回收,所有線程都活動時,因為隊列沒有限制大小,新任務會等待執行。

  2. 【前方高能,筆者腦洞】FixThreadPool其實就像一堆人排隊上公廁一樣,可以無數多人排隊,但是廁所位置就那么多,而且沒人上時,廁所也不會被拆遷,哈哈o(∩_∩)o ,很形象吧。

  3. 由於線程不會回收,FixThreadPool會更快地響應外界請求,這也很容易理解,就好像有人突然想上廁所,公廁不是現用現建的。

2.2 SingleThreadPool(公廁里只有一個坑位)

/*
*@SingleThreadPool介紹
*@author SEU_Calvin
* @date 2016/09/03
*/
public static ExecutorService newSingleThreadPool (int nThreads){
    return new FinalizableDelegatedExecutorService ( new ThreadPoolExecutor (1, 1, 0, TimeUnit. MILLISECONDS, new LinkedBlockingQueue<Runnable>()) );
}
//使用
Executors.newSingleThreadPool ().execute(r);
  1. 從配置參數可以看出,SingleThreadPool只有一個核心線程,確保所有任務都在同一線程中按順序完成。因此不需要處理線程同步的問題。

  2. 【前方高能,筆者腦洞】可以把SingleThreadPool簡單的理解為FixThreadPool的參數被手動設置為1的情況,即Executors.newFixThreadPool(1).execute(r)。所以SingleThreadPool可以理解為公廁里只有一個坑位,先來先上。為什么只有一個坑位呢,因為這個公廁是收費的,收費的大爺上年紀了,只能管理一個坑位,多了就管不過來了(線程同步問題)。

2.3 CachedThreadPool(一堆人去一家很大的咖啡館喝咖啡)

/*
*@CachedThreadPool介紹
*@author SEU_Calvin
* @date 2016/09/03
*/
public static ExecutorService newCachedThreadPool(int nThreads){
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit. SECONDS, new SynchronousQueue<Runnable>());
}
//使用
Executors.newCachedThreadPool().execute(r);
  1. CachedThreadPool只有非核心線程,最大線程數非常大,所有線程都活動時,會為新任務創建新線程,否則利用空閑線程(60s空閑時間,過了就會被回收,所以線程池中有0個線程的可能)處理任務。

  2. 任務隊列SynchronousQueue相當於一個空集合,導致任何任務都會被立即執行。

  3. 【前方高能,筆者腦洞】CachedThreadPool就像是一堆人去一個很大的咖啡館喝咖啡,里面服務員也很多,隨時去,隨時都可以喝到咖啡。但是為了響應國家的“光盤行動”,一個人喝剩下的咖啡會被保留60秒,供新來的客人使用,哈哈哈哈哈,好惡心啊。如果你運氣好,沒有剩下的咖啡,你會得到一杯新咖啡。但是以前客人剩下的咖啡超過60秒,就變質了,會被服務員回收掉。

  4. 比較適合執行大量的耗時較少的任務。喝咖啡人挺多的,喝的時間也不長。

2.4 ScheduledThreadPool(4個里面唯一一個有延遲執行和周期重復執行的線程池)

/*
*@ScheduledThreadPool介紹
*@author SEU_Calvin
* @date 2016/09/03
*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize){
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedQueue ());
}
//使用,延遲1秒執行,每隔2秒執行一次Runnable r
Executors. newScheduledThreadPool (5).scheduleAtFixedRate(r, 1000, 2000, TimeUnit.MILLISECONDS);
  1. 核心線程數固定,非核心線程(閑着沒活干會被立即回收)數沒有限制。

  2. 從上面代碼也可以看出,ScheduledThreadPool主要用於執行定時任務以及有固定周期的重復任務。

至此Android中最常見的四類不同特性的線程池內容總結完畢。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM