0.前言併發
轉載請註明出處:http://blog.csdn.net/seu_calvin/article/details/52415337性能
使用線程池能夠給咱們帶來不少好處,首先經過線程池中線程的重用,減小建立和銷燬線程的性能開銷。其次,能控制線程池中的併發數,不然會由於大量的線程爭奪CPU資源形成阻塞。最後,線程池可以對線程進行管理,好比使用ScheduledThreadPool來設置延遲N秒後執行任務,而且每隔M秒循環執行一次。spa
下面會經過介紹線程池中的真正實現者——ThreadPoolExecutor來引出Android中的4類線程池的使用以及特性分析,會加上筆者本身的理解,和自認爲比較恰當的比喻,幫助理解。.net
1.凡事得靠ThreadPoolExecutor(鋪墊環節,懂的直接跳過)線程
Executor做爲一個接口,它的具體實現就是ThreadPoolExecutor。code
Android中的線程池都是直接或間接經過配置ThreadPoolExecutor來實現不一樣特性的線程池。對象
先介紹ThreadPoolExecutor的一個經常使用的構造方法。blog
1 /* 2 *@ ThreadPoolExecutor構造參數介紹 3 *@author SEU_Calvin 4 * @date 2016/09/03 5 */ 6 public ThreadPoolExecutor( 7 //核心線程數,除非allowCoreThreadTimeOut被設置爲true,不然它閒着也不會死 8 int corePoolSize, 9 //最大線程數,活動線程數量超過它,後續任務就會排隊 10 int maximumPoolSize, 11 //超時時長,做用於非核心線程(allowCoreThreadTimeOut被設置爲true時也會同時做用於核心線程),閒置超時便被回收 12 long keepAliveTime, 13 //枚舉類型,設置keepAliveTime的單位,有TimeUnit.MILLISECONDS(ms)、TimeUnit. SECONDS(s)等 14 TimeUnit unit, 15 //緩衝任務隊列,線程池的execute方法會將Runnable對象存儲起來 16 BlockingQueue<Runnable> workQueue, 17 //線程工廠接口,只有一個new Thread(Runnable r)方法,可爲線程池建立新線程 18 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(一堆人排隊上公廁)
1 /* 2 *@FixThreadPool介紹 3 *@author SEU_Calvin 4 * @date 2016/09/03 5 */ 6 public static ExecutorService newFixThreadPool(int nThreads){ 7 return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); 8 } 9 //使用 10 Executors.newFixThreadPool(5).execute(r);
(1)從配置參數來看,FixThreadPool只有核心線程,而且數量固定的,也不會被回收,全部線程都活動時,由於隊列沒有限制大小,新任務會等待執行。
(2)【前方高能,筆者腦洞】FixThreadPool其實就像一堆人排隊上公廁同樣,能夠無數多人排隊,可是廁所位置就那麼多,並且沒人上時,廁所也不會被拆遷,哈哈o(∩_∩)o ,很形象吧。
(3)因爲線程不會回收,FixThreadPool會更快地響應外界請求,這也很容易理解,就好像有人忽然想上廁所,公廁不是現用現建的。
2.2 SingleThreadPool(公廁裏只有一個坑位)
1 /* 2 *@SingleThreadPool介紹 3 *@author SEU_Calvin 4 * @date 2016/09/03 5 */ 6 public static ExecutorService newSingleThreadPool (int nThreads){ 7 return new FinalizableDelegatedExecutorService ( new ThreadPoolExecutor (1, 1, 0, TimeUnit. MILLISECONDS, new LinkedBlockingQueue<Runnable>()) ); 8 } 9 //使用 10 Executors.newSingleThreadPool ().execute(r);
(1)從配置參數能夠看出,SingleThreadPool只有一個核心線程,確保全部任務都在同一線程中按順序完成。所以不須要處理線程同步的問題。
(2)【前方高能,筆者腦洞】能夠把SingleThreadPool簡單的理解爲FixThreadPool的參數被手動設置爲1的狀況,即Executors.newFixThreadPool(1).execute(r)。因此SingleThreadPool能夠理解爲公廁裏只有一個坑位,先來先上。爲何只有一個坑位呢,由於這個公廁是收費的,收費的大爺上年紀了,只能管理一個坑位,多了就管不過來了(線程同步問題)。
2.3 CachedThreadPool(一堆人去一家很大的咖啡館喝咖啡)
1 /* 2 *@CachedThreadPool介紹 3 *@author SEU_Calvin 4 * @date 2016/09/03 5 */ 6 public static ExecutorService newCachedThreadPool(int nThreads){ 7 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit. SECONDS, new SynchronousQueue<Runnable>()); 8 } 9 //使用 10 Executors.newCachedThreadPool().execute(r);
(1)CachedThreadPool只有非核心線程,最大線程數很是大,全部線程都活動時,會爲新任務建立新線程,不然利用空閒線程(60s空閒時間,過了就會被回收,因此線程池中有0個線程的可能)處理任務。
(2)任務隊列SynchronousQueue至關於一個空集合,致使任何任務都會被當即執行。
(3)【前方高能,筆者腦洞】CachedThreadPool就像是一堆人去一個很大的咖啡館喝咖啡,裏面服務員也不少,隨時去,隨時均可以喝到咖啡。可是爲了響應國家的「光盤行動」,一我的喝剩下的咖啡會被保留60秒,供新來的客人使用,哈哈哈哈哈,好惡心啊。若是你運氣好,沒有剩下的咖啡,你會獲得一杯新咖啡。可是之前客人剩下的咖啡超過60秒,就變質了,會被服務員回收掉。
(4)比較適合執行大量的耗時較少的任務。喝咖啡人挺多的,喝的時間也不長。
2.4 ScheduledThreadPool(4個裏面惟一一個有延遲執行和週期重複執行的線程池)
1 /* 2 *@ScheduledThreadPool介紹 3 *@author SEU_Calvin 4 * @date 2016/09/03 5 */ 6 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize){ 7 return new ScheduledThreadPoolExecutor(corePoolSize); 8 } 9 public ScheduledThreadPoolExecutor(int corePoolSize){ 10 super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedQueue ()); 11 } 12 //使用,延遲1秒執行,每隔2秒執行一次Runnable r 13 Executors. newScheduledThreadPool (5).scheduleAtFixedRate(r, 1000, 2000, TimeUnit.MILLISECONDS);
(1)核心線程數固定,非核心線程(閒着沒活幹會被當即回收)數沒有限制。
(2)從上面代碼也能夠看出,ScheduledThreadPool主要用於執行定時任務以及有固定週期的重複任務。
至此Android中最多見的四類不一樣特性的線程池內容總結完畢。
轉載請註明出處:http://blog.csdn.net/seu_calvin/article/details/52415337