Java線程池(一):初識

一、什麼是線程池?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

相關文章
相關標籤/搜索