一、线程池

线程池 = 存放多个线程的 “池子”。程序需要执行任务时,直接从池子里一个线程;任务执行完,线程不销毁,放回池子复用

线程池的作用:

  • 避免频繁创建 / 销毁线程(非常耗资源)
  • 控制并发线程数量(防止服务器卡死)
  • 统一管理线程(监控、调优、拒绝策略)

线程池 = 线程复用 + 控制并发 + 资源管理

Java 内置线程池的核心工具

  • ExecutorService —— 线程池接口
  • ThreadPoolExecutor —— 线程池真正实现类(最常用)

二、线程池 7 大核心参数

new ThreadPoolExecutor(
    int corePoolSize,      // 核心线程数(常驻线程)
    int maximumPoolSize,   // 最大线程数
    long keepAliveTime,    // 非核心线程空闲多久被销毁
    TimeUnit unit,         // 时间单位
    BlockingQueue<Runnable> workQueue, // 任务队列
    ThreadFactory threadFactory,       // 线程工厂(命名线程)
    RejectedExecutionHandler handler    // 拒绝策略
)

执行流程(超级重要)

  1. 任务进来 → 核心线程未满 → 创建核心线程执行
  2. 核心线程满了 → 任务放进队列排队
  3. 队列满了 → 创建非核心线程执行
  4. 总线程达到最大 → 执行拒绝策略

三、最常用的 4 种线程池(简单好用)

Java 通过 Executors 工具类快速创建:

1. FixedThreadPool(固定线程数)

适合:已知并发压力的任务

ExecutorService pool = Executors.newFixedThreadPool(5);

2. CachedThreadPool(自动扩容)

适合:大量短生命周期任务

ExecutorService pool = Executors.newCachedThreadPool();

3. ScheduledThreadPool(定时任务)

适合:定时、周期性执行任务

ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);

4. SingleThreadExecutor(单线程)

适合:需要顺序执行的任务

ExecutorService pool = Executors.newSingleThreadExecutor();

四、拒绝策略(线程满了怎么办)

4 种内置策略:

  1. AbortPolicy(默认):直接抛异常
  2. CallerRunsPolicy:让提交任务的线程自己执行
  3. DiscardPolicy:直接丢掉任务
  4. DiscardOldestPolicy:丢掉队列最老的任务

真实开发常用:CallerRunsPolicy(最安全)

五、线程池大小如何设置?

  • CPU 密集型核心数 + 1
  • IO 密集型核心数 * 2 或更多(因为 IO 会等待)

例:4 核 CPU

  • 计算任务 → 核心线程 5
  • 网络 / 数据库 → 核心线程 8~10

六、生产环境最佳线程池配置

1. 核心原则

禁止Executors快捷创建,直接手动ThreadPoolExecutor实例化,规避 OOM 风险;按业务类型区分线程池,隔离任务互不影响。

2. 参数取值规范

参数 IO 密集型 CPU 密集型 说明
核心线程 CPU 核数 ×2 CPU 核数 + 1 常驻核心,保障基础吞吐
最大线程 核心 ×4 等于核心 IO 可扩容应对突发峰值
空闲存活 60s 0s 闲置线程及时回收,节省资源
阻塞队列 ArrayBlockingQueue(200) 固定队列 100 有界队列,杜绝无限堆积 OOM
线程工厂 自定义命名 自定义命名 便于日志排查问题
拒绝策略 CallerRunsPolicy CallerRunsPolicy 不丢任务,降级由调用方执行

3. 队列选型

  • ArrayBlockingQueue:有界队列,固定容量,生产首选,可控内存
  • 禁用SynchronousQueue、无界LinkedBlockingQueue,极易引发内存溢出

4. 拒绝策略选型

生产首选CallerRunsPolicy

  • 优势:不会丢弃业务任务,削峰限流保护服务
  • 禁用默认 AbortPolicy 频繁抛异常、Discard 系列丢失数据

5. 生产运维要点

  • 线程池拆分:业务、定时、异步消息各自独立池,避免互相阻塞
  • 监控埋点:监控线程活跃数、队列积压、拒绝次数、执行耗时
  • 优雅关闭:应用下线调用shutdown(),等待任务收尾
  • 动态调参:压测后根据实际 QPS、耗时微调核心数与队列大小

6. 避坑总结

  • 不使用 Executors 创建线程池
  • 队列必须设固定上限
  • 业务分类隔离线程池
  • 自定义线程名,方便问题定位
  • 拒绝策略优先调用者执行,保障数据不丢失

更多推荐