本文的整體結(jié)構(gòu)如下所示。

Java線程池核心原理
看過Java線程池源碼的小伙伴都知道,在Java線程池中最核心的類就是ThreadPoolExecutor,而在ThreadPoolExecutor類中最核心的構(gòu)造方法就是帶有7個參數(shù)的構(gòu)造方法,如下所示。
publicThreadPoolExecutor(intcorePoolSize, intmaximumPoolSize, longkeepAliveTime, TimeUnitunit, BlockingQueueworkQueue, ThreadFactorythreadFactory, RejectedExecutionHandlerhandler)
各參數(shù)的含義如下所示。
corePoolSize:線程池中的常駐核心線程數(shù)。
maximumPoolSize:線程池能夠容納同時執(zhí)行的最大線程數(shù),此值大于等于1。
keepAliveTime:多余的空閑線程存活時間,當(dāng)空間時間達(dá)到keepAliveTime值時,多余的線程會被銷毀直到只剩下corePoolSize個線程為止。
unit:keepAliveTime的單位。
workQueue:任務(wù)隊列,被提交但尚未被執(zhí)行的任務(wù)。
threadFactory:表示生成線程池中工作線程的線程工廠,用戶創(chuàng)建新線程,一般用默認(rèn)即可。
handler:拒絕策略,表示當(dāng)線程隊列滿了并且工作線程大于等于線程池的最大顯示數(shù)(maxnumPoolSize)時,如何來拒絕請求執(zhí)行的runnable的策略。
并且Java的線程池是通過 生產(chǎn)者-消費者模式 實現(xiàn)的,線程池的使用方是生產(chǎn)者,而線程池本身就是消費者。
Java線程池的核心工作流程如下圖所示。

手?jǐn)]Java線程池
我們自己手動實現(xiàn)的線程池要比Java自身的線程池簡單的多,我們?nèi)サ袅烁鞣N復(fù)雜的處理方式,只保留了最核心的原理:線程池的使用者向任務(wù)隊列中添加任務(wù),而線程池本身從任務(wù)隊列中消費任務(wù)并執(zhí)行任務(wù)。

只要理解了這個核心原理,接下來的代碼就簡單多了。在實現(xiàn)這個簡單的線程池時,我們可以將整個實現(xiàn)過程進(jìn)行拆解。拆解后的實現(xiàn)流程為:定義核心字段、創(chuàng)建內(nèi)部類WorkThread、創(chuàng)建ThreadPool類的構(gòu)造方法和創(chuàng)建執(zhí)行任務(wù)的方法。

定義核心字段
首先,我們創(chuàng)建一個名稱為ThreadPool的Java類,并在這個類中定義如下核心字段。
DEFAULT_WORKQUEUE_SIZE:靜態(tài)常量,表示默認(rèn)的阻塞隊列大小。
workQueue:模擬實際的線程池使用阻塞隊列來實現(xiàn)生產(chǎn)者-消費者模式。
workThreads:模擬實際的線程池使用List集合保存線程池內(nèi)部的工作線程。
核心代碼如下所示。
//默認(rèn)阻塞隊列大小 privatestaticfinalintDEFAULT_WORKQUEUE_SIZE=5; //模擬實際的線程池使用阻塞隊列來實現(xiàn)生產(chǎn)者-消費者模式 privateBlockingQueueworkQueue; //模擬實際的線程池使用List集合保存線程池內(nèi)部的工作線程 privateList workThreads=newArrayList ();
創(chuàng)建內(nèi)部類WordThread
在ThreadPool類中創(chuàng)建一個內(nèi)部類WorkThread,模擬線程池中的工作線程。主要的作用就是消費workQueue中的任務(wù),并執(zhí)行任務(wù)。由于工作線程需要不斷從workQueue中獲取任務(wù),所以,這里使用了while(true)循環(huán)不斷嘗試消費隊列中的任務(wù)。
核心代碼如下所示。
//內(nèi)部類WorkThread,模擬線程池中的工作線程
//主要的作用就是消費workQueue中的任務(wù),并執(zhí)行
//由于工作線程需要不斷從workQueue中獲取任務(wù),使用了while(true)循環(huán)不斷嘗試消費隊列中的任務(wù)
classWorkThreadextendsThread{
@Override
publicvoidrun(){
//不斷循環(huán)獲取隊列中的任務(wù)
while(true){
//當(dāng)沒有任務(wù)時,會阻塞
try{
RunnableworkTask=workQueue.take();
workTask.run();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
創(chuàng)建ThreadPool類的構(gòu)造方法
這里,我們?yōu)門hreadPool類創(chuàng)建兩個構(gòu)造方法,一個構(gòu)造方法中傳入線程池的容量大小和阻塞隊列,另一個構(gòu)造方法中只傳入線程池的容量大小。
核心代碼如下所示。
//在ThreadPool的構(gòu)造方法中傳入線程池的大小和阻塞隊列 publicThreadPool(intpoolSize,BlockingQueueworkQueue){ this.workQueue=workQueue; //創(chuàng)建poolSize個工作線程并將其加入到workThreads集合中 IntStream.range(0,poolSize).forEach((i)->{ WorkThreadworkThread=newWorkThread(); workThread.start(); workThreads.add(workThread); }); } //在ThreadPool的構(gòu)造方法中傳入線程池的大小 publicThreadPool(intpoolSize){ this(poolSize,newLinkedBlockingQueue<>(DEFAULT_WORKQUEUE_SIZE)); }
創(chuàng)建執(zhí)行任務(wù)的方法
在ThreadPool類中創(chuàng)建執(zhí)行任務(wù)的方法execute(),execute()方法的實現(xiàn)比較簡單,就是將方法接收到的Runnable任務(wù)加入到workQueue隊列中。
核心代碼如下所示。
//通過線程池執(zhí)行任務(wù)
publicvoidexecute(Runnabletask){
try{
workQueue.put(task);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
完整源碼
這里,我們給出手動實現(xiàn)的ThreadPool線程池的完整源代碼,如下所示。
packageio.binghe.thread.pool;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.concurrent.BlockingQueue;
importjava.util.concurrent.LinkedBlockingQueue;
importjava.util.stream.IntStream;
/**
*@authorbinghe
*@version1.0.0
*@description自定義線程池
*/
publicclassThreadPool{
//默認(rèn)阻塞隊列大小
privatestaticfinalintDEFAULT_WORKQUEUE_SIZE=5;
//模擬實際的線程池使用阻塞隊列來實現(xiàn)生產(chǎn)者-消費者模式
privateBlockingQueueworkQueue;
//模擬實際的線程池使用List集合保存線程池內(nèi)部的工作線程
privateListworkThreads=newArrayList();
//在ThreadPool的構(gòu)造方法中傳入線程池的大小和阻塞隊列
publicThreadPool(intpoolSize,BlockingQueueworkQueue){
this.workQueue=workQueue;
//創(chuàng)建poolSize個工作線程并將其加入到workThreads集合中
IntStream.range(0,poolSize).forEach((i)->{
WorkThreadworkThread=newWorkThread();
workThread.start();
workThreads.add(workThread);
});
}
//在ThreadPool的構(gòu)造方法中傳入線程池的大小
publicThreadPool(intpoolSize){
this(poolSize,newLinkedBlockingQueue<>(DEFAULT_WORKQUEUE_SIZE));
}
//通過線程池執(zhí)行任務(wù)
publicvoidexecute(Runnabletask){
try{
workQueue.put(task);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
//內(nèi)部類WorkThread,模擬線程池中的工作線程
//主要的作用就是消費workQueue中的任務(wù),并執(zhí)行
//由于工作線程需要不斷從workQueue中獲取任務(wù),使用了while(true)循環(huán)不斷嘗試消費隊列中的任務(wù)
classWorkThreadextendsThread{
@Override
publicvoidrun(){
//不斷循環(huán)獲取隊列中的任務(wù)
while(true){
//當(dāng)沒有任務(wù)時,會阻塞
try{
RunnableworkTask=workQueue.take();
workTask.run();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
}
沒錯,我們僅僅用了幾十行Java代碼就實現(xiàn)了一個極簡版的Java線程池,沒錯,這個極簡版的Java線程池的代碼卻體現(xiàn)了Java線程池的核心原理。
接下來,我們測試下這個極簡版的Java線程池。
編寫測試程序
測試程序也比較簡單,就是通過在main()方法中調(diào)用ThreadPool類的構(gòu)造方法,傳入線程池的大小,創(chuàng)建一個ThreadPool類的實例,然后循環(huán)10次調(diào)用ThreadPool類的execute()方法,向線程池中提交的任務(wù)為:打印當(dāng)前線程的名稱--->> Hello ThreadPool。
整體測試代碼如下所示。
packageio.binghe.thread.pool.test;
importio.binghe.thread.pool.ThreadPool;
importjava.util.stream.IntStream;
/**
*@authorbinghe
*@version1.0.0
*@description測試自定義線程池
*/
publicclassThreadPoolTest{
publicstaticvoidmain(String[]args){
ThreadPoolthreadPool=newThreadPool(10);
IntStream.range(0,10).forEach((i)->{
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"--->>HelloThreadPool");
});
});
}
}
接下來,運行ThreadPoolTest類的main()方法,會輸出如下信息。
Thread-0--->>HelloThreadPool Thread-9--->>HelloThreadPool Thread-5--->>HelloThreadPool Thread-8--->>HelloThreadPool Thread-4--->>HelloThreadPool Thread-1--->>HelloThreadPool Thread-2--->>HelloThreadPool Thread-5--->>HelloThreadPool Thread-9--->>HelloThreadPool Thread-0--->>HelloThreadPool
至此,我們自定義的Java線程池就開發(fā)完成了。
總結(jié)
線程池的核心原理其實并不復(fù)雜,只要我們耐心的分析,深入其源碼理解線程池的核心本質(zhì),你就會發(fā)現(xiàn)線程池的設(shè)計原來是如此的優(yōu)雅。希望通過這個手寫線程池的小例子,能夠讓你更好的理解線程池的核心原理。
審核編輯:劉清
-
JAVA
+關(guān)注
關(guān)注
20文章
3004瀏覽量
116755 -
線程池
+關(guān)注
關(guān)注
0文章
58瀏覽量
7416
原文標(biāo)題:10分鐘帶你徒手做個Java線程池
文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
動態(tài)流量池數(shù)據(jù)資源交付技術(shù):破解網(wǎng)絡(luò)流量調(diào)度的核心難題
生產(chǎn)環(huán)境數(shù)據(jù)庫連接池耗盡的全流程排查與性能優(yōu)化實戰(zhàn)
全棧國產(chǎn)AI Coding上線:摩爾線程+硅基流動+智譜,強強聯(lián)合!
解析Linux的進(jìn)程、線程和協(xié)程
開放協(xié)作,共筑生態(tài)——思爾芯參與上海開放處理器產(chǎn)業(yè)創(chuàng)新中心開業(yè)儀式暨RISC-V專利聯(lián)盟專利池入池儀式
C語言內(nèi)存池使用
多線程的系統(tǒng)
Linux多線程對比單線程的優(yōu)勢
Arm Neoverse CPU上大代碼量Java應(yīng)用的性能測試
數(shù)據(jù)全復(fù)用高性能池化層設(shè)計思路分享
沉砂池物聯(lián)網(wǎng)監(jiān)控管理系統(tǒng)方案
Java效率提升指南:5個Java工具選型建議及Perforce JRebel和XRebel介紹
Task任務(wù):LuatOS實現(xiàn)“任務(wù)級并發(fā)”的核心引擎
摩爾線程“AI工廠”:五大核心技術(shù)支撐,打造大模型訓(xùn)練超級工廠
Java線程池核心原理
評論