Java中的線程池用ThreadPoolExecutor類來表示,ThreadPoolExecutor這個類繼承自抽象類AbstractExecutorService,AbstractExecutorService又實現了ExecutorService接口,ExecutorService接口又繼承了Executor接口。數組
ThreadPoolExecutor類詳細說明在本博客中其餘篇幅有介紹,若是須要請參考緩存
從參數即可以看到幾個構造方式的不一樣,可是若跟源碼以後,會發現,前面三個都調用了第四個。安全
跟源碼以後會發現,其實這些靜態方法裏面也是調用了ThreadPoolExecutor的構造方法,例如:數據結構
只不過Executors幫咱們配置了一些參數;下面介紹下Executors方式:併發
一、newCachedThreadPool 方法,它建立了一個可緩存的線程池,若是線程池的長度超過處理須要,它可靈活回收空閒線程,若無可回收,則新建線程。spa
2、newScheduledThreadPool 方法,它建立了一個定長線程池,支持定時及週期性的任務執行。線程
三、newFixedThreadPool 方法,它建立了一個定長線程池,能夠控制線程最大併發數,超出的線程會在隊列中等待。繼承
四、newSingleThreadExecutor 方法,它建立了一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部的任務按照指定的順序(FIFO, LIFO, 優先級)來執行的。接口
首先,咱們一塊兒來建立一個能夠緩存的線程池,若是線程池的長度超過了處理須要的話,它可靈活的回收空閒的線程,若無可回收的線程,則就新建線程。代碼如圖1所示:生命週期
當前線程:pool-1-thread-1輸出:0
當前線程:pool-1-thread-1輸出:1
當前線程:pool-1-thread-1輸出:2
當前線程:pool-1-thread-1輸出:3
當前線程:pool-1-thread-1輸出:4
當前線程:pool-1-thread-1輸出:5
當前線程:pool-1-thread-1輸出:6
當前線程:pool-1-thread-1輸出:7
當前線程:pool-1-thread-1輸出:8
當前線程:pool-1-thread-1輸出:9
以上第一種方式建立線程池,線程池爲無限大的,當其執行到第二個任務的時候,第一個任務已經完成了,而且會複用執行第一個任務的線程,進而不用每次新建線程。
改變下,去掉睡眠,註釋掉,輸出結果
//Thread.sleep(i*1000);
當前線程:pool-1-thread-1輸出:0
當前線程:pool-1-thread-3輸出:2
當前線程:pool-1-thread-3輸出:9
當前線程:pool-1-thread-5輸出:4
當前線程:pool-1-thread-7輸出:6
當前線程:pool-1-thread-2輸出:1
當前線程:pool-1-thread-9輸出:8
當前線程:pool-1-thread-6輸出:5
當前線程:pool-1-thread-8輸出:7
當前線程:pool-1-thread-4輸出:3
去掉休眠,這種方式將會建立1-10個線程,獲取cup時間片執行
而後,咱們一塊兒來建立一個定長的線程池,這個線程池它支持定時及週期性的任務執行。延遲執行的示例代碼如下圖所示:表示延遲3秒執行代碼。
當前線程:pool-1-thread-1輸出:0
當前線程:pool-1-thread-1輸出:2
當前線程:pool-1-thread-3輸出:1
當前線程:pool-1-thread-3輸出:4
當前線程:pool-1-thread-1輸出:3
當前線程:pool-1-thread-2輸出:5
當前線程:pool-1-thread-2輸出:6
當前線程:pool-1-thread-2輸出:7
當前線程:pool-1-thread-2輸出:9
當前線程:pool-1-thread-4輸出:8
以下圖:表示延遲1秒後,每隔5秒執行一次代碼即每隔5秒重複執行一次
當前線程:pool-1-thread-4輸出:3
當前線程:pool-1-thread-1輸出:0
當前線程:pool-1-thread-5輸出:4
當前線程:pool-1-thread-2輸出:1
當前線程:pool-1-thread-2輸出:8
當前線程:pool-1-thread-2輸出:9
當前線程:pool-1-thread-3輸出:2
當前線程:pool-1-thread-5輸出:7
當前線程:pool-1-thread-1輸出:6
當前線程:pool-1-thread-4輸出:5
當前線程:pool-1-thread-2輸出:0
當前線程:pool-1-thread-1輸出:3
當前線程:pool-1-thread-4輸出:4
當前線程:pool-1-thread-5輸出:2
當前線程:pool-1-thread-2輸出:6
當前線程:pool-1-thread-2輸出:8
當前線程:pool-1-thread-2輸出:9
當前線程:pool-1-thread-3輸出:1
當前線程:pool-1-thread-5輸出:7
當前線程:pool-1-thread-4輸出:5
而後,咱們一塊兒來建立一個定長的線程池,能夠控制線程的最大併發數,超出的任務會在隊列中等待。示例代碼以下圖所示:
以上第三種方式建立線程池,由於線程池大小爲4,每一個任務輸出index後sleep 3秒,因此每3秒打印4個數字。
定長線程池的大小最好根據系統資源進行設置。如Runtime.getRuntime().availableProcessors()
最後,咱們一塊兒來建立一個單線程化的線程池,單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)來執行。示例代碼如圖:
當前線程:pool-1-thread-1輸出:0
當前線程:pool-1-thread-1輸出:1
當前線程:pool-1-thread-1輸出:2
當前線程:pool-1-thread-1輸出:3
當前線程:pool-1-thread-1輸出:4
當前線程:pool-1-thread-1輸出:5
當前線程:pool-1-thread-1輸出:6
當前線程:pool-1-thread-1輸出:7
當前線程:pool-1-thread-1輸出:8
當前線程:pool-1-thread-1輸出:9
代碼的結果是依次輸出的,就至關因而按順序的執行了各個任務。
runState表示當前線程池的狀態。
當線程池初始建立的時候,是running態。
當線程池處於shutdown態的時候,此線程池不可以接受新的任務,它會等待全部的任務執行完畢。
當線程池處於stop狀態的時候,此線程不能接受新的任務,而且會去嘗試終止正在執行的任務。
那線程池何時處於什麼狀態呢。當調用了shutdown()方法的時候就會處於shutdown狀態,當調用了shutdownNow()方法的時候就會處於stop狀態。
線程池中的線程是有數量限制的,根據任務類型來設置線程數量,若是是CPU密集型,則數量爲NCPU+1,若是是IO密集型,則數量爲2*NCPU,不少時候,爲了安全性,仍是會設置上限,當新的任務來的時候,若是正常數量的線程都在用着,那麼就用一個隊列數據結構把新的任務緩存起來,如果新任務增加速度大於線程完成任務的速度,這時能夠在線程數量尚未達到上限的時候建立新的線程來執行任務,但如果達到了上限並且任務緩存隊列已經滿了的話,則有必要採起拒絕措施,拒絕後續任務的到來。
這裏有兩個概念:
1)任務緩存隊列(詳細介紹在本博客其餘篇幅有詳細介紹,若有須要請參考)
常有這四種狀況,咱們選用一個東西的時候確定是根據它的某些特徵。
A、ArrayBlockingQueue:基於數組的先進先出隊列,此隊列建立時必須指定大小。
B、PriorityBlockingQueue:基於優先級的隊列。
C、LinkedBlockingQueue:基於鏈表的先進先出隊列,若是建立時沒有指定大小,則默認爲Integer.MAX_VALUE。
D、synchronousQueue:這個隊列比較特殊,它不會保存提交的任務,而是將直接新建一個線程來執行新的任務。
2)任務的拒絕措施:若是線程池中任務緩存隊列已經滿了而且線程池中線程數目達到maxmunPoolSize,若是還有任務來,就會採起任務拒絕策略,一般有一些四種策略。
A、ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異常。
B、ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,可是不拋出異常。
C、ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,而後從新嘗試執行任務(重複此過程)
D、ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務
附錄:返回ExecutorService接口
ExecutorService接口方法
ExecutorService實現類
頂層Executor接口的,最終在ThreadPoolExecutor裏面有了具體的實現,這個方法就是用來讓線程池執行某個任務的。