Skip to content

ThreadPool

更新: 3/4/2026 字数: 0 字

Java 并发包(java.util.concurrent)中,Executors 提供了 5 种常用的内置线程池,所有线程池底层均基于 ThreadPoolExecutor(除 ForkJoinPool 外)实现,只是参数配置不同。

线程池是一种生产者 - 消费者模式

示例代码

java
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class MyThreadPool {

    // 利用阻塞队列实现生产者-消费者模式
    BlockingQueue<Runnable> workQueue;
    // 保存内部工作线程
    List<WorkerThread> threads = new ArrayList<>();

    // 构造方法
    MyThreadPool(int poolSize, BlockingQueue<Runnable> workQueue) {
        this.workQueue = workQueue;
        // 创建工作线程
        for (int idx = 0; idx < poolSize; idx++) {
            WorkerThread work = new WorkerThread();
            work.start();
            threads.add(work);
        }
    }

    // 提交任务
    void execute(Runnable command) {
        try {
            workQueue.put(command);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    // 工作线程负责消费任务,并执行任务
    class WorkerThread extends Thread {
        public void run() {
            // 循环取任务并执行
            while (true) {
                try {
                    Runnable task = workQueue.take();
                    task.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    static void main() {
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);
        MyThreadPool pool = new MyThreadPool(10, workQueue);
        for (int i = 0; i < 100; i++) {
            pool.execute(() -> {
                System.out.println("hello" + UUID.randomUUID().toString());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }
}

内置线程池分类(核心 6 种)

1. 固定线程池(FixedThreadPool)

核心代码 & 参数

java
// 创建方式
ExecutorService executor = Executors.newFixedThreadPool(int nThreads);

// 底层实现(简化)
new ThreadPoolExecutor(
    nThreads,                          // 核心线程数 = 最大线程数
    nThreads,                          // 最大线程数
    0L,                                // 非核心线程存活时间(0,无意义)
    TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>() // 无界工作队列
);

核心特性

  • 线程数固定,核心线程数 = 最大线程数,无临时线程
  • 任务队列是无界的 LinkedBlockingQueue,超出线程数的任务全部入队等待
  • 核心线程不会自动销毁,即使空闲也会一直存活(除非线程池关闭)

适用场景

  • CPU 密集型任务(如计算、排序),线程数建议设为 CPU 核心数 + 1
  • 任务数可控、执行时间稳定的场景(避免无界队列导致内存溢出)

2. 缓存线程池(CachedThreadPool)

核心代码 & 参数

java
// 创建方式
ExecutorService executor = Executors.newCachedThreadPool();

// 底层实现(简化)
new ThreadPoolExecutor(
    0,                                  // 核心线程数 = 0
    Integer.MAX_VALUE,                  // 最大线程数(理论无限)
    60L,                                // 临时线程空闲 60 秒后销毁
    TimeUnit.SECONDS,
    new SynchronousQueue<Runnable>()    // 同步队列(无容量,任务直接移交)
);

核心特性

  • 无核心线程,全部是临时线程,线程数可动态扩展(理论上无上限)
  • 任务队列是 SynchronousQueue(同步队列),无存储能力,提交的任务必须有线程立即接收,否则创建新线程
  • 空闲线程超过 60 秒自动销毁,避免资源浪费

适用场景

  • IO 密集型任务(如网络请求、文件读写),任务执行时间短、数量波动大
  • 需快速处理大量短期任务的场景(如临时批量处理)

风险

若任务提交速度远大于处理速度,会创建大量线程,可能导致 OutOfMemoryError(线程数过多)。

3. 单线程线程池(SingleThreadExecutor)

核心代码 & 参数

java
// 创建方式
ExecutorService executor = Executors.newSingleThreadExecutor();

// 底层实现(简化)
new ThreadPoolExecutor(
    1,                                  // 核心线程数 = 1
    1,                                  // 最大线程数 = 1
    0L,
    TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>() // 无界队列
);

核心特性

  • 只有 1 个核心线程,所有任务串行执行
  • 若唯一线程异常终止,会自动创建新线程替代,保证任务持续执行
  • 任务队列无界,任务按提交顺序执行

适用场景

  • 需保证任务按顺序执行的场景(如日志写入、订单处理)
  • 需单线程处理任务,但希望线程异常后自动恢复的场景(优于手动创建单线程)

4. 定时线程池(ScheduledThreadPoolExecutor)

核心代码 & 参数

java
// 创建方式
ScheduledExecutorService executor = Executors.newScheduledThreadPool(int corePoolSize);

// 底层实现:继承 ThreadPoolExecutor,扩展定时逻辑
new ScheduledThreadPoolExecutor(
    corePoolSize,                       // 核心线程数
    // 最大线程数=Integer.MAX_VALUE,任务队列=DelayedWorkQueue(延迟队列)
);

核心特性

  • 支持延迟执行、周期性执行任务
  • 底层队列是 DelayedWorkQueue(延迟队列),按任务到期时间排序
  • 核心线程数固定,临时线程数无上限(空闲 10 秒后销毁)

核心 API

java
// 延迟 delay 时间后执行一次
executor.schedule(Runnable command, long delay, TimeUnit unit);

// 延迟 initialDelay 后,每隔 period 时间执行一次(固定频率)
executor.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);

// 上一次任务执行完后,隔 delay 时间执行下一次(固定间隔)
executor.scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);

适用场景

  • 定时任务(如定时备份、定时清理缓存)
  • 周期性任务(如心跳检测、数据同步)

5. 单线程定时线程池(SingleThreadScheduledExecutor)

核心代码

java
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

核心特性

  • 是 ScheduledThreadPoolExecutor 的单线程版本
  • 所有定时 / 周期性任务串行执行,保证顺序
  • 线程异常终止时自动创建新线程

适用场景

  • 需串行执行的定时任务(如单线程处理定时消息)

6. 分叉 / 合并线程池(ForkJoinPool)

核心代码

java
// JDK8+ 推荐方式(获取公共池)
ForkJoinPool pool = ForkJoinPool.commonPool();

// 自定义线程数
ForkJoinPool pool = new ForkJoinPool(int parallelism);

核心特性

  • 基于「分治思想」设计,适用于可拆分的大任务(如大数据量计算)
  • 线程数默认等于 CPU 核心数,支持工作窃取(Work Stealing):空闲线程从繁忙线程的队列中窃取任务执行,提升效率
  • 底层基于 ForkJoinTask(可拆分 / 合并的任务)

适用场景

  • 大数据量并行计算(如数组求和、排序、文件遍历)
  • 任务可拆分为多个子任务,且子任务可独立执行的场景

线程池对比表

线程池类型核心线程数最大线程数任务队列核心特性适用场景
FixedThreadPool自定义= 核心线程数LinkedBlockingQueue(无界)线程数固定,串行排队CPU 密集型、任务数可控
CachedThreadPool0Integer.MAX_VALUESynchronousQueue(同步)动态扩缩容,无核心线程IO 密集型、短期任务
SingleThreadExecutor11LinkedBlockingQueue(无界)单线程串行执行,自动恢复任务需顺序执行
ScheduledThreadPool自定义Integer.MAX_VALUEDelayedWorkQueue(延迟)支持延迟 / 周期性执行定时 / 周期性任务
SingleThreadScheduledExecutor11DelayedWorkQueue(延迟)单线程定时执行串行定时任务
ForkJoinPoolCPU 核心数CPU 核心数工作窃取队列分治 + 工作窃取,并行计算大数据量可拆分任务

使用注意事项

  • 避免使用无界队列的线程池(FixedThreadPool/SingleThreadExecutor):若任务提交速度远大于处理速度,无界队列会导致内存溢出(OOM)
  • CachedThreadPool 慎用:极端情况下会创建大量线程,导致系统资源耗尽
  • 优先自定义 ThreadPoolExecutor:内置线程池参数固定,实际开发中建议根据业务场景自定义核心线程数、队列、拒绝策略
  • ForkJoinPool 适配场景:仅适用于可拆分的任务,普通任务使用反而增加开销

总结

  • 核心分类:Java 内置线程池主要包括固定、缓存、单线程、定时、分叉合并 5 类(单线程定时是定时线程池的特例)
  • 底层统一:除 ForkJoinPool 外,其余均基于 ThreadPoolExecutor,仅参数配置不同
  • 选型原则:根据任务类型(CPU/IO 密集)、执行方式(串行 / 并行)、调度需求(定时 / 即时)选择对应线程池
  • 生产建议:优先自定义 ThreadPoolExecutor,避免内置线程池的参数固化问题