0.前言併發
轉載請註明出處:http://blog.csdn.net/seu_calvin/article/details/52415337性能
使用線程池能夠給咱們帶來不少好處,首先經過線程池中線程的重用,減小建立和銷燬線程的性能開銷。其次,能控制線程池中的併發數,不然會由於大量的線程爭奪CPU資源形成阻塞。最後,線程池可以對線程進行管理,好比使用ScheduledThreadPool來設置延遲N秒後執行任務,而且每隔M秒循環執行一次。.net
下面會經過介紹線程池中的真正實現者——ThreadPoolExecutor來引出Android中的4類線程池的使用以及特性分析,會加上筆者本身的理解,和自認爲比較恰當的比喻,幫助理解。線程
1.凡事得靠ThreadPoolExecutor(鋪墊環節,懂的直接跳過)對象
Executor做爲一個接口,它的具體實現就是ThreadPoolExecutor。blog
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表示線程池中當前線程數量)get
(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中常見的線程池有四種,FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor。
FixedThreadPool線程池是經過Executors的new FixedThreadPool方法來建立。它的特色是該線程池中的線程數量是固定的。即便線程處於閒置的狀態,它們也不會被回收,除非線程池被關閉。當全部的線程都處於活躍狀態的時候,新任務就處於隊列中等待線程來處理。注意,FixedThreadPool只有核心線程,沒有非核心線程。
CachedThreadPool線程池是經過Executors的newCachedThreadPool進行建立的。它是一種線程數目不固定的線程池,它沒有核心線程,只有非核心線程,當線程池中的線程都處於活躍狀態,就會建立新的線程來處理新的任務。不然就會利用閒置的線程來處理新的任務。線程池中的線程都有超時機制,這個超時機制時長是60s,超過這個時間,閒置的線程就會被回收。這種線程池適合處理大量而且耗時較少的任務。這裏得說一下,CachedThreadPool的任務隊列,基本都是空的。
ScheduledThreadPool線程池是經過Executors的newScheduledThreadPool進行建立的,它的核心線程是固定的,可是非核心線程數是不固定的,而且當非核心線程一處於空閒狀態,就當即被回收。這種線程適合執行定時任務和具備固定週期的重複任務。
------------------------------------------------------------------------------------------------
SingleThreadExecutor線程池是經過Executors的newSingleThreadExecutor方法來建立的,這類線程池中只有一個核心線程,也沒有非核心線程,這就確保了全部任務可以在同一個線程而且按照順序來執行,這樣就不須要考慮線程同步的問題。
至此Android中最多見的四類不一樣特性的線程池內容總結完畢。 ------------------------------------------------------------------------------------------------