跳转到内容

1. Java 线程池原理


线程池是一种池化技术,用于预先创建并管理一组线程,避免频繁创建和销毁线程的开销,提高性能和响应速度。 它几个关键的配置包括:核心线程数最大线程数空闲存活时间工作队列拒绝策略

image-20250901153706765

主要工作原理如下:

  1. 默认情况下线程不会预创建,任务提交之后才会创建线程(不过设置 prestartAllCoreThreads 可以预创建核心线程)。
  2. 当核心线程满了之后不会新建线程,而是把任务堆积到工作队列中。
  3. 如果工作队列放不下了,然后才会新增线程,直至达到最大线程数。
  4. 如果工作队列满了,然后也已经达到最大线程数了,这时候来任务会执行拒绝策略。
  5. 如果线程空闲时间超过空闲存活时间,并且当前线程数大于核心线程数的则会销毁线程,直到线程数等于核心线程数(设置 allowCoreThreadTimeOuttrue 可以回收核心线程,默认为 false)。

任务提交,线程池中线程总数还未达到核心线程数;

image-20250901154446562

核心线程数已满,任务队列尚未满;

image-20250901154635958

核心线程数已满,且任务队列已满;

image-20250901154831177

线程池中线程已达到最大线程数,且任务队列已满。

image-20250901155223965

ThreadPoolExecutor 里,默认情况下核心线程是懒加载的,只有在提交任务时才会创建。而 prestartAllCoreThreads() 的作用就是一次性启动线程池里的所有核心线程,让它们提前就绪,等待任务。

  • prestartCoreThread()启动 一个 核心线程(如果还有没创建的核心线程)。
  • prestartAllCoreThreads()启动 所有 核心线程,返回实际启动的线程数。
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 10,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>()
);
// 默认情况下还没有线程被创建
System.out.println("初始线程数: " + executor.getPoolSize()); // 0
// 预启动所有核心线程
int started = executor.prestartAllCoreThreads();
System.out.println("当前线程数: " + executor.getPoolSize()); // 5

3. 处理线程退出(processWorkerExit

Section titled “3. 处理线程退出(processWorkerExit)”

processWorkerExit 的作用是在线程池中,当一个工作线程正常完成任务、空闲超时被回收或非正常退出时,负责清理该线程(从线程池集合移除、更新线程计数)、检查线程池状态,并在必要时补充新线程以保证线程池能够持续处理队列中的任务。

image-20250901164538053

当一个线程完成任务或者被中断/空闲超时退出时,processWorkerExit 会负责:

  1. 减少线程池中当前线程计数

    workerCount 会原子减一,保证线程池统计准确。

  2. 从线程集合中移除 Worker

    workers.remove(worker),避免池里保存已经退出的线程对象。

  3. 判断是否需要创建新的线程

    如果线程池仍在运行状态,并且任务队列里还有待处理任务,可能创建新的线程去处理队列中的任务,保证线程池维持一定数量线程。

  4. 更新最大线程数统计

    largestPoolSize 用于监控线程池历史峰值。

  5. 通知等待线程/唤醒线程池管理器

    让其它线程知道有线程退出,有可能触发重新创建线程或执行拒绝策略。

队列类型队列容量核心线程满了怎么办适合场景
LinkedBlockingQueue可以无限放任务直接排队等线程空闲执行CPU 密集型、任务量可控
ArrayBlockingQueue有上限队列满了就创建非核心线程控制线程数量、防止内存爆掉
SynchronousQueue不存储任务每个任务必须直接交给线程执行高并发短任务、尽量不缓存
DelayQueue / PriorityBlockingQueue有上限或按优先级控制按延迟时间或优先级顺序取任务定时任务或优先级任务