一篇了解線程池

一、ThreadPoolExecutor 核心與 Executors 工廠方法

ThreadPoolExecutor 是 Java java.util.concurrent 包下線程池的核心實(shí)現(xiàn)類,負(fù)責(zé)線程的創(chuàng)建、復(fù)用、調(diào)度與銷毀。Executors 工具類提供靜態(tài)工廠方法,簡化線程池創(chuàng)建,本質(zhì)是封裝 ThreadPoolExecutor 的參數(shù)配置。

核心構(gòu)造方法(7 大參數(shù))

public ThreadPoolExecutor(
    int corePoolSize,          // 核心線程數(shù)(常駐存活)
    int maximumPoolSize,       // 最大線程數(shù)
    long keepAliveTime,        // 非核心線程空閑超時時間
    TimeUnit unit,             // 時間單位
    BlockingQueue<Runnable> workQueue, // 任務(wù)阻塞隊列
    ThreadFactory threadFactory,      // 線程工廠(自定義線程名/優(yōu)先級)
    RejectedExecutionHandler handler  // 拒絕策略
)

標(biāo)準(zhǔn)工作流程

任務(wù)提交 → 核心線程未滿 → 創(chuàng)建核心線程執(zhí)行
核心線程滿 → 任務(wù)入 workQueue 等待
隊列滿 → 且線程數(shù) < 最大線程數(shù) → 創(chuàng)建非核心線程執(zhí)行
隊列滿 + 線程數(shù)達(dá)最大 → 執(zhí)行 拒絕策略(Abort/CallerRuns/DiscardOldest/Discard)

二、Executors 四大常用內(nèi)置線程池(基于 ThreadPoolExecutor)

1. newFixedThreadPool:固定大小線程池

創(chuàng)建方法:Executors.newFixedThreadPool(int nThreads)
核心配置:
corePoolSize = maximumPoolSize = nThreads(無非核心線程)
keepAliveTime = 0(線程永久存活)
隊列:LinkedBlockingQueue(無界隊列,容量 Integer.MAX_VALUE)
特點(diǎn):線程數(shù)固定、并發(fā)可控、空閑線程不銷毀
適用場景:CPU 密集型任務(wù)(數(shù)據(jù)計算、圖像處理)、穩(wěn)定長期并發(fā)、需嚴(yán)格控制線程數(shù)
風(fēng)險:無界隊列 → 任務(wù)堆積導(dǎo)致 OOM

2. newCachedThreadPool:可緩存線程池

創(chuàng)建方法:Executors.newCachedThreadPool()
核心配置:
corePoolSize = 0(無核心線程)
maximumPoolSize = Integer.MAX_VALUE(理論無限線程)
keepAliveTime = 60s(空閑 60s 銷毀)
隊列:SynchronousQueue(同步隊列,不存儲任務(wù),直接移交)
特點(diǎn):自動擴(kuò)容、線程復(fù)用、空閑自動回收
適用場景:大量短期異步小任務(wù)、負(fù)載輕、突發(fā)高并發(fā)、響應(yīng)快
風(fēng)險:無限線程 → 高并發(fā)下創(chuàng)建過多線程導(dǎo)致 CPU 飆升 / 線程耗盡

3. newSingleThreadExecutor:單線程線程池

創(chuàng)建方法:Executors.newSingleThreadExecutor()
核心配置:
corePoolSize = maximumPoolSize = 1(僅 1 個線程)
keepAliveTime = 0
隊列:LinkedBlockingQueue(無界)
特點(diǎn):串行執(zhí)行所有任務(wù)、無并發(fā)、順序保證
適用場景:需嚴(yán)格順序執(zhí)行的任務(wù)(日志寫入、文件處理、串行業(yè)務(wù))
風(fēng)險:單線程阻塞 → 所有任務(wù)排隊;無界隊列 → OOM

4. newScheduledThreadPool:定時 / 周期性線程池

創(chuàng)建方法:Executors.newScheduledThreadPool(int corePoolSize)
核心配置:
基于 ScheduledThreadPoolExecutor(繼承 ThreadPoolExecutor)
corePoolSize 固定,maximumPoolSize = Integer.MAX_VALUE
隊列:DelayedWorkQueue(延遲隊列,按延遲時間排序)
特點(diǎn):支持 延遲執(zhí)行、固定頻率 / 固定延遲周期執(zhí)行
適用場景:定時任務(wù)(每日統(tǒng)計、定時備份)、周期性心跳、超時檢測
風(fēng)險:任務(wù)執(zhí)行過長 → 周期任務(wù)堆積;最大線程無界 → 線程風(fēng)險

5. 四大線程池參數(shù)對比

image.png

三、ThreadPoolTaskExecutor(Spring 封裝線程池)

1. 定位與本質(zhì)

Spring 對 ThreadPoolExecutor 的生產(chǎn)級封裝,實(shí)現(xiàn) TaskExecutor 接口,深度集成 Spring 容器,是 Spring 異步(@Async)默認(rèn)線程池。

2. 核心優(yōu)勢(對比原生 ThreadPoolExecutor)

Spring 生態(tài)集成:支持 XML / 注解配置、依賴注入、生命周期管理(隨 Spring 啟動 / 銷毀)
配置更友好:提供 corePoolSize/maxPoolSize/queueCapacity/keepAliveSeconds 等簡化屬性
監(jiān)控與擴(kuò)展:內(nèi)置線程池監(jiān)控(活躍線程、隊列大小、任務(wù)完成數(shù))、支持線程上下文傳播
拒絕策略 / 線程工廠:可直接配置,無需手動構(gòu)造

3. 常用配置(JavaConfig)

@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);          // 核心線程
        executor.setMaxPoolSize(10);          // 最大線程
        executor.setQueueCapacity(100);       // 隊列容量(有界,避免OOM)
        executor.setKeepAliveSeconds(60);     // 空閑時間
        executor.setThreadNamePrefix("async-");// 線程名前綴
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

4. 適用場景

Spring Boot/Spring 項(xiàng)目、@Async 異步方法、消息監(jiān)聽器、Web 異步處理、需 Spring 管理的并發(fā)任務(wù)。

實(shí)現(xiàn)方式

1 注解式異步(聲明式異步)
只需要在方法上加 @Async,Spring 自動把方法變成異步,Spring 自動提交給線程池,Spring 自動返回 future(java.util.concurrent.Future 未來結(jié)果對象)
優(yōu)點(diǎn):
代碼極簡
業(yè)務(wù)代碼干凈,看不到線程池
適合簡單異步:發(fā)消息、發(fā)短信、記錄日志
缺點(diǎn):
不夠靈活
不適合大批量并發(fā)、復(fù)雜編排
超時、異常、批量等待不如你現(xiàn)在的寫法方便


@Async("reportTaskExecutor")
    public void sendLog(String msg){
        // 異步記錄日志,主線程直接返回
    }

適用常見如:異步存日志,此寫法與切面(@Aspect) 可二選一,@Async 是 Spring 提供的開箱即用異步工具,它底層就是 Spring AOP 切面,而寫切面(@Aspect) 需要 @Pointcut切點(diǎn)攔截, @Around環(huán)繞通知,高度自定義。
2 手動聲明異步(聲明式異步)
CompletableFuture.runAsync(任務(wù), 線程池)

//引入線程池
@Qualifier("detectionTaskExecutor")
private ThreadPoolTaskExecutor detectionTaskExecutor;

//手動線程池,保證線程可控
    public boolean doDetectionInterface(String flowId) {
        List<Map<String, String>> detectionPoints = newReportDao.getAllDetectionForReport();
        List<Map<String, String>> accounts = newReportDao.getAllAccountForReport();

        if (detectionPoints.isEmpty() || accounts.isEmpty()) {
            log.warn("沒有檢測到需要處理的數(shù)據(jù),檢測點(diǎn)數(shù)量:{},賬號數(shù)量:{}",
                    detectionPoints.size(), accounts.size());
            return false;
        }

        log.info("開始執(zhí)行檢測任務(wù),流水號:{},檢測點(diǎn)數(shù)量:{},重保賬號數(shù)量:{}",
                flowId, detectionPoints.size(), accounts.size());
        // 使用CompletableFuture管理異步任務(wù)
        CompletableFuture<?>[] futures = accounts.stream()
                .flatMap(account -> detectionPoints.stream()
                        .map(detectionPoint -> CompletableFuture.runAsync(
                                () -> executeSingleDetection(
                                        flowId,
                                        account.get("accountId"),
                                        detectionPoint.get("cpName"),
                                        detectionPoint.get("classIndex")
                                ),
                                detectionTaskExecutor
                        ))
                )
                .toArray(CompletableFuture[]::new);

        // 等待所有任務(wù)完成
        try {
            CompletableFuture.allOf(futures).get(TASK_TIMEOUT_MINUTES, TimeUnit.MINUTES);
            log.info("所有檢測任務(wù)已完成,流水號:{}", flowId);
            return true;
        } catch (TimeoutException e) {
            log.error("檢測任務(wù)執(zhí)行超時,流水號:{}", flowId, e);
            return false;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
            log.error("檢測任務(wù)被中斷,流水號:{}", flowId, e);
            return false;
        } catch (ExecutionException e) {
            log.error("檢測任務(wù)執(zhí)行異常,流水號:{}", flowId, e.getCause());
            return false;
        }
    }

四、EagerThreadPool(Dubbo 急切線程池)

1. 定位與來源

Dubbo 自定義線程池(org.apache.dubbo.common.threadpool.support.eager),核心是 EagerThreadPoolExecutor(繼承 ThreadPoolExecutor)。

2. 核心創(chuàng)新:顛覆標(biāo)準(zhǔn)線程池流程

原生流程:核心滿 → 入隊列 → 隊列滿 → 擴(kuò)容到最大線程
Eager 流程:核心滿 → 直接擴(kuò)容到最大線程 → 線程滿 → 再入隊列

3. 實(shí)現(xiàn)原理

自定義 TaskQueue(繼承 LinkedBlockingQueue):重寫 offer () → 線程數(shù) < 最大時,強(qiáng)制返回 false(入隊失?。?,觸發(fā)線程擴(kuò)容
重寫 execute():捕獲拒絕異常 → 重試入隊 → 仍失敗才拋拒絕異常
維護(hù) submittedTaskCount:統(tǒng)計已提交未完成任務(wù)數(shù)

4. 核心配置(Dubbo)

<dubbo:protocol threadpool="eager" corethreads="4" threads="8" queues="100" alive="60000"/>

corethreads:核心線程
threads:最大線程
queues:隊列容量(Eager 下線程滿才入隊)

5. 特點(diǎn)與適用場景

特點(diǎn):優(yōu)先線程擴(kuò)容、減少隊列等待、降低響應(yīng)延遲
適用場景:RPC / 微服務(wù)短平快調(diào)用(<100ms)、突發(fā)高并發(fā)(秒殺 / 峰值)、對延遲敏感的核心業(yè)務(wù)
風(fēng)險:高并發(fā)下快速達(dá)最大線程 → 線程資源消耗大;需合理設(shè)置最大線程數(shù)

五、關(guān)鍵對比與選型建議

1. Executors 四大內(nèi)置池 vs 自定義 ThreadPoolExecutor

Executors:簡單易用、快速開發(fā);生產(chǎn)禁用(無界隊列 / 無界線程 → OOM / 線程耗盡)
自定義 ThreadPoolExecutor:生產(chǎn)推薦,手動設(shè)置 coreSize/maxSize/有界隊列(ArrayBlockingQueue)/ 拒絕策略,可控安全

2. ThreadPoolTaskExecutor vs EagerThreadPool

ThreadPoolTaskExecutor:Spring 通用、配置靈活、生態(tài)友好 → Spring 項(xiàng)目首選
EagerThreadPool:Dubbo 專屬、低延遲、優(yōu)先線程 → RPC 高并發(fā)、低延遲場景

3. 選型總結(jié)

CPU 密集:FixedThreadPool(自定義有界)
IO 密集 / 短期任務(wù):CachedThreadPool(自定義 max 線程)
串行任務(wù):SingleThreadExecutor(自定義有界)
定時任務(wù):ScheduledThreadPool
Spring 項(xiàng)目:ThreadPoolTaskExecutor
Dubbo 高并發(fā) RPC:EagerThreadPool

4.ThreadPoolExecutor與EagerThreadPool 區(qū)別一圖解釋

image.png

適用場景
常規(guī)線程池更適合
CPU 密集型:計算多、IO 少,線程數(shù)不宜過多
流量穩(wěn)定:任務(wù)提交速度平穩(wěn),隊列可平滑緩沖
內(nèi)存敏感:希望嚴(yán)格控制內(nèi)存,避免線程數(shù)失控
Eager 線程池更適合
IO 密集型:網(wǎng)絡(luò) / DB 調(diào)用多、線程常阻塞,需要快速擴(kuò)容
低延遲要求:如外賣下單、支付、實(shí)時通知,不允許任務(wù)排隊
突發(fā)流量:短時間高并發(fā),需要快速拉起線程扛量
餓了么 / 美團(tuán) / 電商:訂單、支付、履約等核心鏈路

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一:Executor知識點(diǎn) 二:線程池模型 1:線程池模型:生產(chǎn)者-消費(fèi)者模式(與一般的池化資源模式不同),線程池...
    zc_sunny閱讀 493評論 0 0
  • (看漢字即可,圖片是源碼,可以選擇性觀看。)~ 什么是線程池 線程池就是一個裝線程的集合。 用官方語言解釋: 線程...
    MCRO閱讀 226評論 0 2
  • 本文目錄 為什么要使用線程池? 線程池參數(shù)詳解 6種常見的線程池 為什么不能直接自動創(chuàng)建線程 如果自定義合適的線程...
    程序員內(nèi)功心法閱讀 267評論 1 3
  • 兩種任務(wù)類型 1.CPU密集型任務(wù) CPU密集型也叫計算密集型,指的是系統(tǒng)的硬盤、內(nèi)存性能相對CPU要好很多...
    Miraitowa_8960閱讀 254評論 0 0
  • 內(nèi)部狀態(tài) 線程有五種狀態(tài):新建,就緒,運(yùn)行,阻塞,死亡,線程池同樣有五種狀態(tài):Running, SHUTDOWN,...
    codingBoyJack閱讀 742評論 0 1

友情鏈接更多精彩內(nèi)容