您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關如何在Java中使用ThreadPoolExecutor,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
線程池主要由以下4個核心組件組成。
線程池管理器:用于創建并管理線程池
工作線程:線程池中執行具體任務的線程
任務接口:用于定義工作線程的調度和執行策略,只有線程實現了該接口,線程中的任務才能被線程池調度
任務隊列:放待處理的任務,新的任務將會不斷被加入隊列中,執行完成的任務將從隊列中移除
如下是線程池的構造方法
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
其中具體參數含義為:
1.corePoolSize:線程池中核心線程的數量
2.maximumPoolSize:線程池中最大線程的數量
3.keepAliveTime:當線程數量超過corePoolSize時,空閑線程的存活時間
4.unit:keepAliveTime的時間單位
5.workQueue:任務隊列,被提交但尚未被執行的任務存放的地方
6.threadFactory:線程工廠,用于創建線程,可使用默認的線程工廠或自定義線程工廠
7.handler:由于任務過多或其他原因導致線程池無法處理時的任務拒絕策略
編寫測試類如下:
public class ThreadPoolSerialTest { public static void main(String[] args) { //核心線程數 int corePoolSize = 2; //最大線程數 int maximumPoolSize = 4; //超過corePoolSize線程數量的線程最大空閑時間 long keepAliveTime = 2; //以秒為時間單位 TimeUnit unit = TimeUnit.SECONDS; //創建工作隊列,用于存放提交的等待執行任務 BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2); ThreadPoolExecutor threadPoolExecutor = null; try { // 1.創建線程池 threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new ThreadPoolExecutor.AbortPolicy()); // 2.循環提交任務 for (int i = 0; i < 6; i++) { //提交任務的索引 final int index = (i+1); threadPoolExecutor.submit(()->{ //線程打印輸出 System.out.println("大家好,我是線程:"+index); try { //模擬線程執行時間,10s Thread.sleep(10000); System.out.println("線程:"+index+"運行完畢"); } catch (InterruptedException e) { e.printStackTrace(); } }); //每個任務提交后休眠500ms再提交下一個任務,用于保證提交順序 Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); } finally { // 3.關閉線程池 threadPoolExecutor.shutdown(); } } }
其中循環了6次,讓線程池執行了6次任務,恰好滿足maximumPoolSize
+workQueue容量
=并發執行任務數
。輸出結果如下:
大家好,我是線程:1
大家好,我是線程:2
大家好,我是線程:5
大家好,我是線程:6
線程:1運行完畢
大家好,我是線程:3
線程:2運行完畢
大家好,我是線程:4
線程:5運行完畢
線程:6運行完畢
線程:3運行完畢
線程:4運行完畢
這段輸出看似沒有規律,其實這里輸出完全是由線程池控制的;下面就來分行解析輸出:
大家好,我是線程:1
大家好,我是線程:2
大家好,我是線程:5
大家好,我是線程:6
1.全新線程池被創建后,有Runnable或CallBack接口的實現被提交給線程池執行;線程池的corePoolSize=2
,此時前兩個任務提交后就立即執行,便輸出了線程1 線程2
;
2.此時仍繼續向線程池提交任務,線程池中workQueue容量=2
,被加入的任務存放到任務隊列中,即把線程3 線程4
存放到了任務隊列中;
3.任務隊列充滿后,仍繼續向線程池提交任務,線程池的maximumPoolSize=4
,除開核心線程數2個外還允許創建4-2
個線程來執行任務,便輸出了線程5 線程6
線程:1運行完畢
大家好,我是線程:3
線程:2運行完畢
大家好,我是線程:4
1.線程:1運行完畢:表示第一個線程任務執行完畢了
2.大家好,我是線程:3:線程1運行完畢后,此時線程池中有一個空閑的線程,第一個進入任務隊列中的任務第一個交給線程處理
3.線程:2運行完畢 大家好,我是線程:4 :和上面線程執行完畢,任務對列中任務執行一致
線程:5運行完畢
線程:6運行完畢
線程:3運行完畢
線程:4運行完畢
因為每一個任務的執行時間控制的是一樣的,此時輸出的內容便是先被線程池執行的任務先執行完畢。
線程池剛被創建時,只是向系統申請一個用于執行線程隊列和管理線程池的資源。在調用execute()添加一個任務時,線程池會按照以下流程執行任務:
正在運行的線程數量a:a<corePoolSize
,線程池立即創建線程并執行任務;若此時a=corePoolSize
,則任務被存放到workQueue任務隊列中,直到任務隊列被充滿
任務隊列workQueue已充滿且正在運行的線程數a:a<maximumPoolSize
,線程池立即創建非核心線程并執行任務;若有任務執行完畢,該任務將被線程池隊列中移除,線程池從隊列中取先入隊的任務執行;當線程處于空閑狀態的時間超過keepAliveTime時間時,正在運行的線程數acorePoolSize<a
,線程池停止空閑的線程。線程池將任務執行完畢后,線程池會收縮到corePoolSize
大小
任務隊列workQueue已充滿且正在運行的線程數a:a=maximumPoolSize
,線程池拒絕執行該任務并拋出RejectExecutionException異常
1. 簡單,只需理解基本的概念,就可以編寫適合于各種情況的應用程序;2. 面向對象;3. 分布性,Java是面向網絡的語言;4. 魯棒性,java提供自動垃圾收集來進行內存管理,防止程序員在管理內存時容易產生的錯誤。;5. 安全性,用于網絡、分布環境下的Java必須防止病毒的入侵。6. 體系結構中立,只要安裝了Java運行時系統,就可在任意處理器上運行。7. 可移植性,Java可以方便地移植到網絡上的不同機器。8.解釋執行,Java解釋器直接對Java字節碼進行解釋執行。
以上就是如何在Java中使用ThreadPoolExecutor,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。