淺談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ù)解析
編寫測(cè)試類如下:
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ù)對(duì)列中任務(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)申請(qǐ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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 詳解Java并發(fā)包中線程池ThreadPoolExecutor
- java多線程CountDownLatch與線程池ThreadPoolExecutor/ExecutorService案例
- java 定時(shí)器線程池(ScheduledThreadPoolExecutor)的實(shí)現(xiàn)
- Java線程池ThreadPoolExecutor原理及使用實(shí)例
- java中ThreadPoolExecutor常識(shí)匯總
- Java ThreadPoolExecutor 線程池的使用介紹
- Java自帶定時(shí)任務(wù)ScheduledThreadPoolExecutor實(shí)現(xiàn)定時(shí)器和延時(shí)加載功能
- Java之ThreadPoolExecutor類詳解
相關(guān)文章
java簡(jiǎn)單實(shí)現(xiàn)計(jì)算器
這篇文章主要為大家詳細(xì)介紹了java簡(jiǎn)單實(shí)現(xiàn)計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
Java方法重載實(shí)現(xiàn)原理及代碼實(shí)例
這篇文章主要介紹了Java方法重載實(shí)現(xiàn)原理及代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Mybatis接口Mapper內(nèi)的方法為啥不能重載嗎
這篇文章主要介紹了Mybatis接口Mapper內(nèi)的方法為啥不能重載嗎,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Java?C++題解leetcode764最大加號(hào)標(biāo)志示例
這篇文章主要為大家介紹了Java?C++題解leetcode764最大加號(hào)標(biāo)志示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
DynamicDataSource怎樣解決多數(shù)據(jù)源的事務(wù)問題
這篇文章主要介紹了DynamicDataSource怎樣解決多數(shù)據(jù)源的事務(wù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
Java concurrency線程池之Callable和Future_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了Java concurrency線程池之Callable和Future,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
Java中JWT令牌實(shí)現(xiàn)登錄驗(yàn)證
本文主要介紹了JWT令牌在Java中實(shí)現(xiàn)登錄驗(yàn)證的方法,JWT是一種自我包含的、無狀態(tài)的認(rèn)證機(jī)制,可以用來在客戶端和服務(wù)器之間傳遞安全可靠的信息,感興趣的可以了解一下2024-12-12
淺談SpringBoot中的Bean初始化方法?@PostConstruct
這篇文章主要介紹了SpringBoot中的Bean初始化方法?@PostConstruct,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11

