一、什麼是線程池?html
簡單粗暴的理解就是:裝着一個或多個線程的容器,咱們稱這個容器爲線程池。java
在現實世界中,有着各類各樣的「池」,例如游泳池、花池等等。那花池來講,裏面種滿了各類各樣的鮮花,花池自己要作的就是提供一片空地,裏面的鮮花是園丁來種植、澆水。不一樣於花池,線程池不單單須要提供一個能夠裝線程的容器,同時還要承擔起管理容器裏中線程的職責(例如,新建線程、使用線程等)。segmentfault
一個簡單的線程池應該至少包含下面4個部分:併發
(1)線程池管理器:建立、銷燬並管理線程池,將工做線程放入線程池中函數
(2)工做線程:一個能夠循環執行任務的線程,在沒有任務時進行等待測試
(3)任務隊列:將沒有處理的任務放在任務隊列中,提供一種緩衝機制this
(4)任務接口:主要用來規定任務的的入口、任務完成後的收尾工做、任務的執行狀態等,工做線程經過該接口調度任務的執行編碼
下面舉一個簡單的例子來理解線程池的工做:spa
將線程比做一個機器人,一個線程池就是有不少機器人的工廠,工廠經過新建機器人、分配任務給機器人等方式管理者工廠中的全部機器人。初始時,工廠中並無機器人。當工廠接到第一個任務時,工廠的管理人員首先新建機器人1號,而後再將任務分配給機器人1號,機器人1號收到任務的命令後就開始工做了。緊接着,工廠接到了第二個任務,管理人員又新建了機器人2號,將第二個任務分配給了機器人2號。當工廠再次接到新的任務時,重複前面的過程。然而,工廠不可能無限制地新建機器人:新建機器人也是須要材料和消耗資源的,資源是有限的;當有新的任務時,前面新建的機器人可能已經完成了交給它的任務而處於空閒狀態,所以能夠將新的任務分配給處於休息狀態的機器人。當工廠中全部的機器人都處於工做狀態時,又來了新的任務,怎麼辦呢?因而,工廠管理者設置了一個任務等候區,新來的任務按順序在等候區排隊。當有機器人完成了任務時,從任務隊列中取出一個任務,分配給空閒的機器人,讓機器人從新處於工做狀態。.net
二、爲何要使用線程池?
從前面工廠的例子中能夠看出,線程池爲咱們帶來了如下好處:
(1)分攤建立線程的開銷,加快對請求的響應速度。接到一個任務時,新建了一個線程用於完成任務。當任務完成後,線程處於空閒狀態,後面再有新的任務時,沒必要再新建線程,處於空閒狀態的線程能夠直接投入工做,省去了新建線程了過程,加快了對請求的響應速度。因爲對線程實現了重用,新建線程的開銷就被分攤到了多個任務上,線程被重用的次數越多,平均分攤到每一個任務中的線程建立的開銷就越少。
(2)解決了資源不足的問題。線程是須要資源的,而資源又是有限的,經過控制線程的數目,避免出現資源不足的問題。
三、如何使用線程池?
線程池有着上面的優點,能夠本身編碼實現一個線程池。然而,編碼實現線程池自己就是一項工做量不小的任務,而咱們的工做重心是要完成實際的業務。同時,本身編碼實現的線程池的正確性、可靠性與穩定性難以保證。因而,大師Doug Lea編寫並開源了一個併發程序的代碼庫,在JDK 1.5以後已加入JDK的豪華套餐,爲 java.util.concurrent包。
在Java中,線程池類爲java.util.concurrent.ThreadPoolExecutor,能夠經過該類建立咱們須要的線程池:
1 public ThreadPoolExecutor(int corePoolSize, 2 int maximumPoolSize, 3 long keepAliveTime, 4 TimeUnit unit, 5 BlockingQueue<Runnable> workQueue, 6 RejectedExecutionHandler handler)
參數說明:
corePoolSize : 線程池維護線程的數量(the number of threads to keep in the pool, even if they are idle.)
maximumPoolSize : 線程池維護線程的最大數量(the maximum number of threads to allow in the pool.)
keepAliveTime : 線程池中的線程容許的最大空閒時間(when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.)
unit : 參數keepAliveTime的時間單位 (the time unit for the keepAliveTime argument.)
workQueue : 任務緩衝隊列(the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.)
handler : 對拒絕任務的處理策略(the handler to use when execution is blocked because the thread bounds and queue capacities are reached.)
經過上面的構造函數,能夠構造一個線程池對象threadPool。在Java中,一個任務就是一個Runnable類的對象,具體的業務處理邏輯在該對象的run()方法中實現。經過threadPoool.execute(Runnable)方法,任務被提交到了線程池中並執行。
【代碼實例】
任務類:
1 package com.code.threadpool; 2 3 import java.io.Serializable; 4 5 public class ThreadPoolTask implements Runnable, Serializable { 6 7 private static final long serialVersionUID = 1L; 8 9 private Object threadPoolTaskData; 10 11 ThreadPoolTask(Object tasks) { 12 this.threadPoolTaskData = tasks; 13 } 14 15 public void run() { 16 System.out.println("start ..." + threadPoolTaskData); 17 try { 18 Thread.sleep(2000); 19 } catch (Exception e) { 20 e.printStackTrace(); 21 } 22 System.out.println("end ..." + threadPoolTaskData); 23 threadPoolTaskData = null; 24 } 25 26 }
線程池測試類:
1 package com.code.threadpool; 2 3 import java.util.concurrent.ArrayBlockingQueue; 4 import java.util.concurrent.ThreadPoolExecutor; 5 import java.util.concurrent.TimeUnit; 6 7 public class ThreadPoolTest { 8 9 /** 10 * 核心線程數量,線程池維護線程的最少數量 11 */ 12 private static final int corePoolSize = 2; 13 14 /** 15 * 線程池維護線程的最大數量 16 */ 17 private static final int maxPoolSize = 4; 18 19 /** 20 * 線程池維護線程所容許的空閒時間 21 */ 22 private static final int keepAliveTime = 3; 23 24 /** 25 * 線程池所使用的緩衝隊列的大小 26 */ 27 private static final int workQueueSize = 3; 28 29 /** 30 * 線程執行任務後sleep的時間,sleep是爲了便於觀察程序的運行結果 31 */ 32 private static final int produceTaskSleepTime = 2; 33 34 /** 35 * 任務的最大數量 36 */ 37 private static final int produceTaskMaxNumber = 10; 38 39 /** 40 * 任務名稱的前綴 41 */ 42 private static final String taskNamePrefix = "task@"; 43 44 public static void main(String[] args) { 45 46 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize, 47 maxPoolSize, keepAliveTime, TimeUnit.SECONDS, 48 new ArrayBlockingQueue<Runnable>(workQueueSize), 49 new ThreadPoolExecutor.DiscardOldestPolicy()); 50 51 for (int i = 0; i < produceTaskMaxNumber; i++) { 52 String taskName = taskNamePrefix + (i + 1); 53 System.out.println(String.format("put %s", taskName)); 54 55 System.out.println("--- before put " + taskName 56 + ", active thread count: " + threadPool.getActiveCount()); 57 ThreadPoolTask task = new ThreadPoolTask(taskName); 58 threadPool.execute(task); 59 System.out.println("--- after put " + taskName 60 + ", active thread count: " + threadPool.getActiveCount()); 61 62 try { 63 Thread.sleep(produceTaskSleepTime); 64 } catch (InterruptedException e) { 65 e.printStackTrace(); 66 } 67 } 68 } 69 70 }
【運行結果】
1 put task@1 2 --- before put task@1, active thread count: 0 3 --- after put task@1, active thread count: 0 4 start ...task@1 5 put task@2 6 --- before put task@2, active thread count: 1 7 --- after put task@2, active thread count: 1 8 start ...task@2 9 put task@3 10 --- before put task@3, active thread count: 2 11 --- after put task@3, active thread count: 2 12 put task@4 13 --- before put task@4, active thread count: 2 14 --- after put task@4, active thread count: 2 15 put task@5 16 --- before put task@5, active thread count: 2 17 --- after put task@5, active thread count: 2 18 put task@6 19 --- before put task@6, active thread count: 2 20 --- after put task@6, active thread count: 2 21 start ...task@6 22 put task@7 23 --- before put task@7, active thread count: 3 24 --- after put task@7, active thread count: 3 25 start ...task@7 26 put task@8 27 --- before put task@8, active thread count: 4 28 --- after put task@8, active thread count: 4 29 put task@9 30 --- before put task@9, active thread count: 4 31 --- after put task@9, active thread count: 4 32 put task@10 33 --- before put task@10, active thread count: 4 34 --- after put task@10, active thread count: 4 35 end ...task@1 36 start ...task@8 37 end ...task@2 38 start ...task@9 39 end ...task@6 40 start ...task@10 41 end ...task@7 42 end ...task@8 43 end ...task@9 44 end ...task@10
參考資料:
一、http://blog.itpub.net/9399028/viewspace-1852029/
二、http://blog.csdn.net/newchenxf/article/details/51996950
三、http://uule.iteye.com/blog/1123185
四、http://www.cnblogs.com/dolphin0520/p/3932921.html
五、https://segmentfault.com/a/1190000007120459
本文爲原創文章,轉載請註明出處:http://www.cnblogs.com/acode/p/6385880.html