淺談Java ThreadPoolExecutor的使用
一、前言
線程池主要由以下4個(gè)核心組件組成。
- 線程池管理器:用于創(chuàng)建并管理線程池
- 工作線程:線程池中執(zhí)行具體任務(wù)的線程
- 任務(wù)接口:用于定義工作線程的調(diào)度和執(zhí)行策略,只有線程實(shí)現(xiàn)了該接口,線程中的任務(wù)才能被線程池調(diào)度
- 任務(wù)隊(duì)列:放待處理的任務(wù),新的任務(wù)將會(huì)不斷被加入隊(duì)列中,執(zhí)行完成的任務(wù)將從隊(duì)列中移除
二、ThreadPoolExecutor
如下是線程池的構(gòu)造方法
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; }
其中具體參數(shù)含義為:
1.corePoolSize:線程池中核心線程的數(shù)量
2.maximumPoolSize:線程池中最大線程的數(shù)量
3.keepAliveTime:當(dāng)線程數(shù)量超過corePoolSize時(shí),空閑線程的存活時(shí)間
4.unit:keepAliveTime的時(shí)間單位
5.workQueue:任務(wù)隊(duì)列,被提交但尚未被執(zhí)行的任務(wù)存放的地方
6.threadFactory:線程工廠,用于創(chuàng)建線程,可使用默認(rèn)的線程工廠或自定義線程工廠
7.handler:由于任務(wù)過多或其他原因?qū)е戮€程池?zé)o法處理時(shí)的任務(wù)拒絕策略
三、構(gòu)造函數(shù)參數(shù)解析
編寫測試類如下:
public class ThreadPoolSerialTest { public static void main(String[] args) { //核心線程數(shù) int corePoolSize = 2; //最大線程數(shù) int maximumPoolSize = 4; //超過corePoolSize線程數(shù)量的線程最大空閑時(shí)間 long keepAliveTime = 2; //以秒為時(shí)間單位 TimeUnit unit = TimeUnit.SECONDS; //創(chuàng)建工作隊(duì)列,用于存放提交的等待執(zhí)行任務(wù) BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2); ThreadPoolExecutor threadPoolExecutor = null; try { // 1.創(chuàng)建線程池 threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new ThreadPoolExecutor.AbortPolicy()); // 2.循環(huán)提交任務(wù) for (int i = 0; i < 6; i++) { //提交任務(wù)的索引 final int index = (i+1); threadPoolExecutor.submit(()->{ //線程打印輸出 System.out.println("大家好,我是線程:"+index); try { //模擬線程執(zhí)行時(shí)間,10s Thread.sleep(10000); System.out.println("線程:"+index+"運(yùn)行完畢"); } catch (InterruptedException e) { e.printStackTrace(); } }); //每個(gè)任務(wù)提交后休眠500ms再提交下一個(gè)任務(wù),用于保證提交順序 Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); } finally { // 3.關(guān)閉線程池 threadPoolExecutor.shutdown(); } } }
其中循環(huán)了6次,讓線程池執(zhí)行了6次任務(wù),恰好滿足maximumPoolSize
+workQueue容量
=并發(fā)執(zhí)行任務(wù)數(shù)
。輸出結(jié)果如下:
大家好,我是線程:1
大家好,我是線程:2
大家好,我是線程:5
大家好,我是線程:6
線程:1運(yùn)行完畢
大家好,我是線程:3
線程:2運(yùn)行完畢
大家好,我是線程:4
線程:5運(yùn)行完畢
線程:6運(yùn)行完畢
線程:3運(yùn)行完畢
線程:4運(yùn)行完畢
這段輸出看似沒有規(guī)律,其實(shí)這里輸出完全是由線程池控制的;下面就來分行解析輸出:
大家好,我是線程:1
大家好,我是線程:2
大家好,我是線程:5
大家好,我是線程:6
1.全新線程池被創(chuàng)建后,有Runnable或CallBack接口的實(shí)現(xiàn)被提交給線程池執(zhí)行;線程池的corePoolSize=2
,此時(shí)前兩個(gè)任務(wù)提交后就立即執(zhí)行,便輸出了線程1 線程2
;
2.此時(shí)仍繼續(xù)向線程池提交任務(wù),線程池中workQueue容量=2
,被加入的任務(wù)存放到任務(wù)隊(duì)列中,即把線程3 線程4
存放到了任務(wù)隊(duì)列中;
3.任務(wù)隊(duì)列充滿后,仍繼續(xù)向線程池提交任務(wù),線程池的maximumPoolSize=4
,除開核心線程數(shù)2個(gè)外還允許創(chuàng)建4-2
個(gè)線程來執(zhí)行任務(wù),便輸出了線程5 線程6
線程:1運(yùn)行完畢
大家好,我是線程:3
線程:2運(yùn)行完畢
大家好,我是線程:4
1.線程:1運(yùn)行完畢:表示第一個(gè)線程任務(wù)執(zhí)行完畢了
2.大家好,我是線程:3:線程1運(yùn)行完畢后,此時(shí)線程池中有一個(gè)空閑的線程,第一個(gè)進(jìn)入任務(wù)隊(duì)列中的任務(wù)第一個(gè)交給線程處理
3.線程:2運(yùn)行完畢 大家好,我是線程:4 :和上面線程執(zhí)行完畢,任務(wù)對列中任務(wù)執(zhí)行一致
線程:5運(yùn)行完畢
線程:6運(yùn)行完畢
線程:3運(yùn)行完畢
線程:4運(yùn)行完畢
因?yàn)槊恳粋€(gè)任務(wù)的執(zhí)行時(shí)間控制的是一樣的,此時(shí)輸出的內(nèi)容便是先被線程池執(zhí)行的任務(wù)先執(zhí)行完畢。
四、總結(jié)
線程池剛被創(chuàng)建時(shí),只是向系統(tǒng)申請一個(gè)用于執(zhí)行線程隊(duì)列和管理線程池的資源。在調(diào)用execute()添加一個(gè)任務(wù)時(shí),線程池會(huì)按照以下流程執(zhí)行任務(wù):
正在運(yùn)行的線程數(shù)量a:a<corePoolSize
,線程池立即創(chuàng)建線程并執(zhí)行任務(wù);若此時(shí)a=corePoolSize
,則任務(wù)被存放到workQueue任務(wù)隊(duì)列中,直到任務(wù)隊(duì)列被充滿
任務(wù)隊(duì)列workQueue已充滿且正在運(yùn)行的線程數(shù)a:a<maximumPoolSize
,線程池立即創(chuàng)建非核心線程并執(zhí)行任務(wù);若有任務(wù)執(zhí)行完畢,該任務(wù)將被線程池隊(duì)列中移除,線程池從隊(duì)列中取先入隊(duì)的任務(wù)執(zhí)行;當(dāng)線程處于空閑狀態(tài)的時(shí)間超過keepAliveTime時(shí)間時(shí),正在運(yùn)行的線程數(shù)acorePoolSize<a
,線程池停止空閑的線程。線程池將任務(wù)執(zhí)行完畢后,線程池會(huì)收縮到corePoolSize
大小
任務(wù)隊(duì)列workQueue已充滿且正在運(yùn)行的線程數(shù)a:a=maximumPoolSize
,線程池拒絕執(zhí)行該任務(wù)并拋出RejectExecutionException異常
到此這篇關(guān)于淺談Java ThreadPoolExecutor的使用的文章就介紹到這了,更多相關(guān)Java ThreadPoolExecutor內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 詳解Java并發(fā)包中線程池ThreadPoolExecutor
- java多線程CountDownLatch與線程池ThreadPoolExecutor/ExecutorService案例
- java 定時(shí)器線程池(ScheduledThreadPoolExecutor)的實(shí)現(xiàn)
- Java線程池ThreadPoolExecutor原理及使用實(shí)例
- java中ThreadPoolExecutor常識匯總
- Java ThreadPoolExecutor 線程池的使用介紹
- Java自帶定時(shí)任務(wù)ScheduledThreadPoolExecutor實(shí)現(xiàn)定時(shí)器和延時(shí)加載功能
- Java之ThreadPoolExecutor類詳解
相關(guān)文章
Mybatis?Mapper中多參數(shù)方法不使用@param注解報(bào)錯(cuò)的解決
這篇文章主要介紹了Mybatis?Mapper中多參數(shù)方法不使用@param注解報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。2022-01-01IDEA自動(dòng)清理類中未使用的import包的操作方法
在項(xiàng)目開發(fā)中,經(jīng)常會(huì)引入很多未使用的import包,這不僅增加了編譯時(shí)間,還會(huì)使代碼可讀性變差,設(shè)置IDEA自動(dòng)清理未使用的import包,可以提高代碼的可讀性,本文給大家介紹IDEA自動(dòng)清理類中未使用的import包的方法,感興趣的朋友一起看看吧2024-09-09C語言中下標(biāo)與指針的轉(zhuǎn)換以及指向指針的指針的例子
這篇文章主要介紹了C語言中下標(biāo)與指針的轉(zhuǎn)換以及指向指針的指針的示例,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-11-11java實(shí)現(xiàn)網(wǎng)上購物車程序
這篇文章主要介紹了java實(shí)現(xiàn)網(wǎng)上購物車程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01spring boot實(shí)戰(zhàn)之本地jar包引用示例
本篇文章主要介紹了spring boot實(shí)戰(zhàn)之本地jar包引用示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10Java 實(shí)現(xiàn)將List平均分成若干個(gè)集合
這篇文章主要介紹了Java 實(shí)現(xiàn)將List平均分成若干個(gè)集合,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08