一篇了解线程池

一、ThreadPoolExecutor 核心与 Executors 工厂方法

ThreadPoolExecutor 是 Java java.util.concurrent 包下线程池的核心实现类,负责线程的创建、复用、调度与销毁。Executors 工具类提供静态工厂方法,简化线程池创建,本质是封装 ThreadPoolExecutor 的参数配置。

核心构造方法(7 大参数)

public ThreadPoolExecutor(
    int corePoolSize,          // 核心线程数(常驻存活)
    int maximumPoolSize,       // 最大线程数
    long keepAliveTime,        // 非核心线程空闲超时时间
    TimeUnit unit,             // 时间单位
    BlockingQueue<Runnable> workQueue, // 任务阻塞队列
    ThreadFactory threadFactory,      // 线程工厂(自定义线程名/优先级)
    RejectedExecutionHandler handler  // 拒绝策略
)

标准工作流程

任务提交 → 核心线程未满 → 创建核心线程执行
核心线程满 → 任务入 workQueue 等待
队列满 → 且线程数 < 最大线程数 → 创建非核心线程执行
队列满 + 线程数达最大 → 执行 拒绝策略(Abort/CallerRuns/DiscardOldest/Discard)

二、Executors 四大常用内置线程池(基于 ThreadPoolExecutor)

1. newFixedThreadPool:固定大小线程池

创建方法:Executors.newFixedThreadPool(int nThreads)
核心配置:
corePoolSize = maximumPoolSize = nThreads(无非核心线程)
keepAliveTime = 0(线程永久存活)
队列:LinkedBlockingQueue(无界队列,容量 Integer.MAX_VALUE)
特点:线程数固定、并发可控、空闲线程不销毁
适用场景:CPU 密集型任务(数据计算、图像处理)、稳定长期并发、需严格控制线程数
风险:无界队列 → 任务堆积导致 OOM

2. newCachedThreadPool:可缓存线程池

创建方法:Executors.newCachedThreadPool()
核心配置:
corePoolSize = 0(无核心线程)
maximumPoolSize = Integer.MAX_VALUE(理论无限线程)
keepAliveTime = 60s(空闲 60s 销毁)
队列:SynchronousQueue(同步队列,不存储任务,直接移交)
特点:自动扩容、线程复用、空闲自动回收
适用场景:大量短期异步小任务、负载轻、突发高并发、响应快
风险:无限线程 → 高并发下创建过多线程导致 CPU 飙升 / 线程耗尽

3. newSingleThreadExecutor:单线程线程池

创建方法:Executors.newSingleThreadExecutor()
核心配置:
corePoolSize = maximumPoolSize = 1(仅 1 个线程)
keepAliveTime = 0
队列:LinkedBlockingQueue(无界)
特点:串行执行所有任务、无并发、顺序保证
适用场景:需严格顺序执行的任务(日志写入、文件处理、串行业务)
风险:单线程阻塞 → 所有任务排队;无界队列 → OOM

4. newScheduledThreadPool:定时 / 周期性线程池

创建方法:Executors.newScheduledThreadPool(int corePoolSize)
核心配置:
基于 ScheduledThreadPoolExecutor(继承 ThreadPoolExecutor)
corePoolSize 固定,maximumPoolSize = Integer.MAX_VALUE
队列:DelayedWorkQueue(延迟队列,按延迟时间排序)
特点:支持 延迟执行、固定频率 / 固定延迟周期执行
适用场景:定时任务(每日统计、定时备份)、周期性心跳、超时检测
风险:任务执行过长 → 周期任务堆积;最大线程无界 → 线程风险

5. 四大线程池参数对比

image.png

三、ThreadPoolTaskExecutor(Spring 封装线程池)

1. 定位与本质

Spring 对 ThreadPoolExecutor 的生产级封装,实现 TaskExecutor 接口,深度集成 Spring 容器,是 Spring 异步(@Async)默认线程池。

2. 核心优势(对比原生 ThreadPoolExecutor)

Spring 生态集成:支持 XML / 注解配置、依赖注入、生命周期管理(随 Spring 启动 / 销毁)
配置更友好:提供 corePoolSize/maxPoolSize/queueCapacity/keepAliveSeconds 等简化属性
监控与扩展:内置线程池监控(活跃线程、队列大小、任务完成数)、支持线程上下文传播
拒绝策略 / 线程工厂:可直接配置,无需手动构造

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 项目、@Async 异步方法、消息监听器、Web 异步处理、需 Spring 管理的并发任务。

实现方式

1 注解式异步(声明式异步)
只需要在方法上加 @Async,Spring 自动把方法变成异步,Spring 自动提交给线程池,Spring 自动返回 future(java.util.concurrent.Future 未来结果对象)
优点:
代码极简
业务代码干净,看不到线程池
适合简单异步:发消息、发短信、记录日志
缺点:
不够灵活
不适合大批量并发、复杂编排
超时、异常、批量等待不如你现在的写法方便


@Async("reportTaskExecutor")
    public void sendLog(String msg){
        // 异步记录日志,主线程直接返回
    }

适用常见如:异步存日志,此写法与切面(@Aspect) 可二选一,@Async 是 Spring 提供的开箱即用异步工具,它底层就是 Spring AOP 切面,而写切面(@Aspect) 需要 @Pointcut切点拦截, @Around环绕通知,高度自定义。
2 手动声明异步(声明式异步)
CompletableFuture.runAsync(任务, 线程池)

//引入线程池
@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("没有检测到需要处理的数据,检测点数量:{},账号数量:{}",
                    detectionPoints.size(), accounts.size());
            return false;
        }

        log.info("开始执行检测任务,流水号:{},检测点数量:{},重保账号数量:{}",
                flowId, detectionPoints.size(), accounts.size());
        // 使用CompletableFuture管理异步任务
        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);

        // 等待所有任务完成
        try {
            CompletableFuture.allOf(futures).get(TASK_TIMEOUT_MINUTES, TimeUnit.MINUTES);
            log.info("所有检测任务已完成,流水号:{}", flowId);
            return true;
        } catch (TimeoutException e) {
            log.error("检测任务执行超时,流水号:{}", flowId, e);
            return false;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
            log.error("检测任务被中断,流水号:{}", flowId, e);
            return false;
        } catch (ExecutionException e) {
            log.error("检测任务执行异常,流水号:{}", flowId, e.getCause());
            return false;
        }
    }

四、EagerThreadPool(Dubbo 急切线程池)

1. 定位与来源

Dubbo 自定义线程池(org.apache.dubbo.common.threadpool.support.eager),核心是 EagerThreadPoolExecutor(继承 ThreadPoolExecutor)。

2. 核心创新:颠覆标准线程池流程

原生流程:核心满 → 入队列 → 队列满 → 扩容到最大线程
Eager 流程:核心满 → 直接扩容到最大线程 → 线程满 → 再入队列

3. 实现原理

自定义 TaskQueue(继承 LinkedBlockingQueue):重写 offer () → 线程数 < 最大时,强制返回 false(入队失败),触发线程扩容
重写 execute():捕获拒绝异常 → 重试入队 → 仍失败才抛拒绝异常
维护 submittedTaskCount:统计已提交未完成任务数

4. 核心配置(Dubbo)

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

corethreads:核心线程
threads:最大线程
queues:队列容量(Eager 下线程满才入队)

5. 特点与适用场景

特点:优先线程扩容、减少队列等待、降低响应延迟
适用场景:RPC / 微服务短平快调用(<100ms)、突发高并发(秒杀 / 峰值)、对延迟敏感的核心业务
风险:高并发下快速达最大线程 → 线程资源消耗大;需合理设置最大线程数

五、关键对比与选型建议

1. Executors 四大内置池 vs 自定义 ThreadPoolExecutor

Executors:简单易用、快速开发;生产禁用(无界队列 / 无界线程 → OOM / 线程耗尽)
自定义 ThreadPoolExecutor:生产推荐,手动设置 coreSize/maxSize/有界队列(ArrayBlockingQueue)/ 拒绝策略,可控安全

2. ThreadPoolTaskExecutor vs EagerThreadPool

ThreadPoolTaskExecutor:Spring 通用、配置灵活、生态友好 → Spring 项目首选
EagerThreadPool:Dubbo 专属、低延迟、优先线程 → RPC 高并发、低延迟场景

3. 选型总结

CPU 密集:FixedThreadPool(自定义有界)
IO 密集 / 短期任务:CachedThreadPool(自定义 max 线程)
串行任务:SingleThreadExecutor(自定义有界)
定时任务:ScheduledThreadPool
Spring 项目:ThreadPoolTaskExecutor
Dubbo 高并发 RPC:EagerThreadPool

4.ThreadPoolExecutor与EagerThreadPool 区别一图解释

image.png

适用场景
常规线程池更适合
CPU 密集型:计算多、IO 少,线程数不宜过多
流量稳定:任务提交速度平稳,队列可平滑缓冲
内存敏感:希望严格控制内存,避免线程数失控
Eager 线程池更适合
IO 密集型:网络 / DB 调用多、线程常阻塞,需要快速扩容
低延迟要求:如外卖下单、支付、实时通知,不允许任务排队
突发流量:短时间高并发,需要快速拉起线程扛量
饿了么 / 美团 / 电商:订单、支付、履约等核心链路

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容