南充建網(wǎng)站的資料下載百度到桌面
線程池是Java多線程編程中的核心組件,用于管理線程的生命周期、復(fù)用線程資源,避免頻繁創(chuàng)建和銷毀線程帶來(lái)的性能開銷。在高并發(fā)場(chǎng)景(如Web服務(wù)器、微服務(wù)調(diào)用等)中,合理使用線程池能顯著提升系統(tǒng)性能和穩(wěn)定性。
1. 為什么需要線程池?
-
問(wèn)題:直接創(chuàng)建線程(
new Thread()
)的缺點(diǎn):-
線程創(chuàng)建和銷毀開銷大(涉及操作系統(tǒng)資源分配)。
-
無(wú)限制創(chuàng)建線程會(huì)導(dǎo)致資源耗盡(如內(nèi)存溢出)。
-
-
解決方案:線程池通過(guò)復(fù)用線程、限制并發(fā)數(shù)、任務(wù)隊(duì)列機(jī)制解決這些問(wèn)題。
2. Java中的線程池實(shí)現(xiàn)
Java通過(guò)java.util.concurrent.ExecutorService
接口及其實(shí)現(xiàn)類提供線程池支持,核心實(shí)現(xiàn)類是ThreadPoolExecutor
。
2.1 線程池的創(chuàng)建(ThreadPoolExecutor)
ThreadPoolExecutor executor = new ThreadPoolExecutor(int corePoolSize, // 核心線程數(shù)(長(zhǎng)期存活的線程)int maximumPoolSize, // 最大線程數(shù)(臨時(shí)線程 = maximumPoolSize - corePoolSize)long keepAliveTime, // 臨時(shí)線程空閑存活時(shí)間TimeUnit unit, // 時(shí)間單位(秒/毫秒等)BlockingQueue<Runnable> workQueue, // 任務(wù)隊(duì)列RejectedExecutionHandler handler // 拒絕策略
);
關(guān)鍵參數(shù)說(shuō)明
參數(shù) | 作用 |
---|---|
corePoolSize | 核心線程數(shù),即使空閑也不會(huì)被銷毀(除非allowCoreThreadTimeOut=true )。 |
maximumPoolSize | 線程池最大能容納的線程數(shù)(核心線程 + 臨時(shí)線程)。 |
keepAliveTime | 臨時(shí)線程空閑時(shí)的存活時(shí)間,超時(shí)后銷毀。 |
workQueue | 任務(wù)隊(duì)列,用于存放待執(zhí)行的任務(wù)(常見隊(duì)列類型見下文)。 |
handler | 當(dāng)線程池和隊(duì)列都滿時(shí),如何處理新任務(wù)(拒絕策略)。 |
2.2 任務(wù)隊(duì)列(BlockingQueue)類型
隊(duì)列類型 | 特性 |
---|---|
ArrayBlockingQueue | 有界隊(duì)列,固定大小,任務(wù)超出隊(duì)列大小時(shí)會(huì)創(chuàng)建臨時(shí)線程。 |
LinkedBlockingQueue | 無(wú)界隊(duì)列(默認(rèn)Integer.MAX_VALUE ),可能導(dǎo)致OOM。 |
SynchronousQueue | 不存儲(chǔ)任務(wù),直接交給線程執(zhí)行(需搭配maximumPoolSize 使用)。 |
PriorityBlockingQueue | 帶優(yōu)先級(jí)的無(wú)界隊(duì)列(任務(wù)需實(shí)現(xiàn)Comparable )。 |
2.3 拒絕策略(RejectedExecutionHandler)
當(dāng)線程池和隊(duì)列都滿時(shí),對(duì)新任務(wù)的處理方式:
策略名 | 行為 |
---|---|
AbortPolicy (默認(rèn)) | 直接拋出RejectedExecutionException 。 |
CallerRunsPolicy | 讓提交任務(wù)的線程自己執(zhí)行該任務(wù)(同步執(zhí)行)。 |
DiscardPolicy | 靜默丟棄任務(wù),不拋異常。 |
DiscardOldestPolicy | 丟棄隊(duì)列中最舊的任務(wù),然后重新嘗試提交當(dāng)前任務(wù)。 |
3. 線程池的工作流程
-
提交任務(wù):調(diào)用
executor.execute(Runnable task)
或submit(Callable task)
。 -
線程分配:
-
如果當(dāng)前線程數(shù) <?
corePoolSize
,立即創(chuàng)建新線程執(zhí)行任務(wù)。 -
如果線程數(shù) ≥?
corePoolSize
,任務(wù)進(jìn)入workQueue
等待。 -
如果隊(duì)列已滿且線程數(shù) <?
maximumPoolSize
,創(chuàng)建臨時(shí)線程執(zhí)行任務(wù)。 -
如果隊(duì)列和線程池均滿,觸發(fā)
拒絕策略
。
-
-
線程回收:
-
核心線程默認(rèn)長(zhǎng)期存活。
-
臨時(shí)線程在空閑
keepAliveTime
后被銷毀。
-
4. 常見的線程池工具類(Executors)
Java提供了Executors
工具類快速創(chuàng)建線程池(但需注意潛在問(wèn)題):
方法名 | 底層實(shí)現(xiàn) | 問(wèn)題 |
---|---|---|
newFixedThreadPool(int n) | 固定大小的線程池(核心=最大線程數(shù),無(wú)界隊(duì)列) | 無(wú)界隊(duì)列可能導(dǎo)致OOM。 |
newCachedThreadPool() | 可擴(kuò)容線程池(核心=0,最大=Integer.MAX_VALUE) | 線程數(shù)無(wú)限制,可能創(chuàng)建過(guò)多線程導(dǎo)致資源耗盡。 |
newSingleThreadExecutor() | 單線程池(核心=最大=1,無(wú)界隊(duì)列) | 無(wú)界隊(duì)列可能導(dǎo)致OOM。 |
newScheduledThreadPool() | 支持定時(shí)/周期性任務(wù)的線程池。 | 無(wú)界隊(duì)列可能導(dǎo)致OOM。 |
建議:生產(chǎn)環(huán)境推薦手動(dòng)創(chuàng)建
ThreadPoolExecutor
,避免使用Executors
的無(wú)界隊(duì)列。
5. 線程池的最佳實(shí)踐
-
合理配置參數(shù):
-
CPU密集型任務(wù):
corePoolSize = CPU核心數(shù) + 1
。 -
IO密集型任務(wù):
corePoolSize = 2 * CPU核心數(shù)
。
-
-
避免無(wú)界隊(duì)列:使用
ArrayBlockingQueue
或自定義有界隊(duì)列。 -
明確拒絕策略:根據(jù)業(yè)務(wù)選擇
AbortPolicy
(日志記錄 + 告警)或CallerRunsPolicy
。 -
監(jiān)控線程池:通過(guò)
ThreadPoolExecutor
的方法(如getActiveCount()
)或Spring Boot Actuator。
6. 示例代碼
// 手動(dòng)創(chuàng)建線程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, // corePoolSize5, // maximumPoolSize60, TimeUnit.SECONDS, // keepAliveTimenew ArrayBlockingQueue<>(10), // 有界隊(duì)列(容量10)new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略
);// 提交任務(wù)
executor.execute(() -> {System.out.println("Task executed by " + Thread.currentThread().getName());
});// 關(guān)閉線程池(平滑關(guān)閉)
executor.shutdown();
7. 常見面試題
-
線程池的底層原理是什么?
-
corePoolSize
和maximumPoolSize
如何協(xié)作? -
無(wú)界隊(duì)列會(huì)導(dǎo)致什么問(wèn)題?
-
如何優(yōu)化線程池參數(shù)?
-
線程池的拒絕策略有哪些?如何選擇?
掌握線程池是Java高并發(fā)編程的基礎(chǔ),也是面試高頻考點(diǎn)。建議結(jié)合源碼(如ThreadPoolExecutor
)和實(shí)際場(chǎng)景(如Web服務(wù)器請(qǐng)求處理)加深理解。