Bootstrap

深入解析 Java 线程池:核心概念、参数、工作流程与实战

1. 什么是线程池?

线程池(Thread Pool) 是 Java 并发编程中的一种优化机制,它通过 复用线程 来减少线程创建与销毁的开销,提高程序的执行效率,适用于 高并发任务处理

线程池的核心优势

  1. 降低资源消耗:复用线程,避免频繁创建和销毁。
  2. 提高响应速度:任务到达时可立即执行,无需等待新线程创建。
  3. 控制并发量:通过线程池大小限制线程数量,防止系统资源耗尽。
  4. 提供管理能力:可设定 任务队列、超时策略、拒绝策略 等。

2. 线程池的核心参数

Java 线程池由 ThreadPoolExecutor 管理,其构造函数包含以下核心参数:

public ThreadPoolExecutor(
    int corePoolSize,    // 核心线程数
    int maximumPoolSize, // 最大线程数
    long keepAliveTime,  // 非核心线程存活时间
    TimeUnit unit,       // 时间单位
    BlockingQueue<Runnable> workQueue, // 任务队列
    ThreadFactory threadFactory,       // 线程工厂
    RejectedExecutionHandler handler   // 拒绝策略
) {
    ...
}

核心参数解析

参数作用
corePoolSize核心线程数,即最小线程数,线程池初始化时默认不创建线程,只有任务到来时才创建
maximumPoolSize线程池最大线程数,超过 corePoolSize 后,任务队列满时才会创建新线程
keepAliveTime线程空闲存活时间,超过 corePoolSize 的额外线程空闲超过该时间后会被销毁
unitkeepAliveTime 的时间单位,如 TimeUnit.SECONDS
workQueue存放等待执行的任务队列,如 LinkedBlockingQueue
threadFactory线程创建工厂,默认为 Executors.defaultThreadFactory()
handler线程池饱和后的 拒绝策略,如 AbortPolicy

3. 线程池的工作流程

线程池的执行逻辑如下

  1. 核心线程池是否已满:未满,则创建新线程执行任务。
  2. 任务队列是否已满:未满,则任务进入队列等待。
  3. 最大线程池是否已满:未满,则创建新的线程执行任务。
  4. 线程池已满,任务队列也已满:触发 拒绝策略 处理。
  5. 空闲线程超过 keepAliveTime:非核心线程会被回收。

4. Java 内置的线程池(Executors 工具类)

Java 提供了 Executors 工具类,封装了几种常见的线程池:

1️⃣ 固定大小线程池(FixedThreadPool)

ExecutorService fixedPool = Executors.newFixedThreadPool(5);

特点

  • 线程数固定,任务队列无限长,适用于 长期执行的固定任务
  • 线程空闲时不会被销毁。

2️⃣ 缓存线程池(CachedThreadPool)

ExecutorService cachedPool = Executors.newCachedThreadPool();

特点

  • 线程数量不固定,空闲 60s 后销毁。
  • 适用于 高并发、短时间任务

3️⃣ 单线程池(SingleThreadExecutor)

ExecutorService singlePool = Executors.newSingleThreadExecutor();

特点

  • 只有一个线程,任务按顺序执行。
  • 适用于 任务串行执行的场景

4️⃣ 定时任务线程池(ScheduledThreadPool)

ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(3);

特点

  • 支持 延迟执行周期执行
  • 适用于 定时任务

示例:

scheduledPool.schedule(() -> System.out.println("延迟任务"), 3, TimeUnit.SECONDS);

5. 线程池的拒绝策略

当线程池达到 maximumPoolSize,且任务队列已满时,会触发 拒绝策略

拒绝策略说明
AbortPolicy默认策略,直接抛出 RejectedExecutionException
CallerRunsPolicy调用线程执行任务,防止丢失
DiscardPolicy直接丢弃新任务,不抛异常
DiscardOldestPolicy丢弃最早的任务,尝试提交新任务

示例:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2, 4, 30, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(10),
    Executors.defaultThreadFactory(),
    new ThreadPoolExecutor.CallerRunsPolicy()
);

6. 线程池实战代码

6.1 自定义线程池

import java.util.concurrent.*;

public class ThreadPoolExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2, 4, 30, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(10),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy()
        );

        for (int i = 0; i < 20; i++) {
            final int taskNum = i;
            executor.execute(() -> {
                System.out.println("执行任务 " + taskNum + " 线程: " + Thread.currentThread().getName());
            });
        }

        executor.shutdown();
    }
}

7. 线程池的常见问题及优化

问题 1:任务堆积导致 OOM

  • 原因:任务过多,队列无限增长。
  • 解决方案:使用 有界队列,限制任务数量。

问题 2:线程泄漏

  • 原因:未正确关闭线程池。
  • 解决方案:调用 shutdown()shutdownNow()

问题 3:CPU 资源浪费

  • 原因maximumPoolSize 设太大,频繁创建/销毁线程。
  • 解决方案:设置合理的 核心线程数

8. 结论

✅ 线程池是 Java 并发编程的核心组件,提供了 线程复用、任务管理 能力。
ThreadPoolExecutor 提供了 参数化控制,可以灵活管理线程生命周期。
Executors 提供了 固定、缓存、单线程、定时 线程池,适用于不同场景。
拒绝策略 保障线程池稳定性,避免任务堆积。

掌握线程池的使用技巧,可以让你的 Java 并发编程更加高效、稳定!🚀

开源一个纯AI生成的健身记录App,如需源码,可关注公众号:小健学Java,回复“健身”即可获得!
如需Java面试题资料,可关注公众号:小健学Java,回复“面试”即可获得!

;