Java 线程池 ThreadPoolExecutor 全面入门(原理 + 核心参数 + 图解)(一)
在 Java 并发编程中,线程池(ThreadPoolExecutor) 是最重要、最常用的组件之一。
如果说 wait/notify 是“线程之间如何协作”,那么线程池就是“如何管理大量线程的创建、复用与调度”。
只要你掌握了线程池的六大核心参数 + 队列类型 + 拒绝策略,你就已经掌握了 Java 并发编程的半壁江山。
一、为什么需要线程池?(必须先讲清楚)
一、为什么需要线程池?(必须先讲清楚)
new Thread(() -> doWork()).start();
但这样会带来很多问题:
- ❌ 创建线程成本高(线程创建需要切栈、注册、调度等)
- ❌ 大量线程会抢占 CPU,造成性能下降
- ❌ JVM 无法控制线程数量,容易 OOM
- ❌ 无法统一管理任务(比如监控、统一关闭等)
- ❌ 不适合高并发(几千、几万任务就炸)
线程池的核心思想是:
把线程复用起来,不用每次都 new Thread,而是把任务交给线程池来调度执行。
二、线程池的核心构造器(ThreadPoolExecutor)
Java 线程池的本体就是:
public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 这六个参数是理解线程池的关键,我给你讲到最透。
三、线程池六大核心参数(绝对核心)
我们逐个讲:
1)corePoolSize(核心线程数)
线程池长期存活的线程数量。
只要提交任务,核心线程池中的线程会一直存在,不会销毁(除了一些 allowCoreThreadTimeout 的特殊情况)。
2)maximumPoolSize(最大线程数)
线程池能创建的最大线程数量(核心线程 + 临时线程)。
- 当任务很多、队列也排满时,会创建临时线程。
- 当任务少时,这些临时线程会被回收。
3)workQueue(任务队列)
核心线程用完后,进入队列等待。
常见队列:
| 队列类型 | 解释 | 特点 |
|---|---|---|
| LinkedBlockingQueue(默认) | 无界队列 | 最常用,但可能 OOM |
| ArrayBlockingQueue | 有界队列 | 强烈推荐用于生产 |
| SynchronousQueue | 不存任务、直接交给线程 | 用于高并发,例如 CachedThreadPool |
| PriorityBlockingQueue | 优先级队列 | 任务可排序 |
队列类型直接决定线程池行为。
4)keepAliveTime(空闲线程存活时间)
临时线程空闲多久后被回收?
只对 非核心线程 生效。
5)threadFactory(线程工厂)
用于给线程自定义:
- 名字(方便排查问题)
- 是否为守护线程
- 优先级
例如:
Executors.defaultThreadFactory()
6)RejectedExecutionHandler(拒绝策略)
当:
- 线程数达到最大(maximumPoolSize)
- 队列也满了
这时任务无法执行,就会触发 拒绝策略。
JDK 提供 4 种:
| 策略 | 行为 |
|---|---|
| AbortPolicy(默认) | 直接抛异常 |
| DiscardPolicy | 直接丢弃任务 |
| DiscardOldestPolicy | 丢弃队列头部任务 |
| CallerRunsPolicy | 由调用者线程执行任务 |
线上一般用 CallerRunsPolicy,让调用线程回退压力。
四、线程池工作流程(图解到你完全懂)
一个任务 submit 到线程池后,会经历以下步骤:
┌──────────────┐ │ 提交任务 │ └──────┬───────┘ ▼ 是否小于 corePoolSize? ├─────────── 是 ─────────→ 创建核心线程执行 │ └── 否 ▼ 队列是否能放下? ├─────────── 是 ─────────→ 进入队列等待 │ └── 否 ▼ 是否小于 maximumPoolSize? ├─────────── 是 ─────────→ 创建临时线程执行 │ └── 否 ▼ 拒绝策略 这张流程图会非常清晰。
五、线程池的四大经典实现(你需要全部掌握)
JDK 自带 Executors 快速创建线程池的方法,但 不推荐 在实际生产使用(因为容易 OOM)。
1)FixedThreadPool(固定线程池)
Executors.newFixedThreadPool(4);
特点:
- 核心线程 = 最大线程
- 无界队列 → 可能 OOM
- 适合 CPU 密集型任务
2)CachedThreadPool(缓存线程池)
Executors.newCachedThreadPool();
特点:
- 核心线程 0
- 最大线程 Integer.MAX_VALUE
- SynchronousQueue(不排队)→ 能创建无限线程 → 极高并发 → 也可能炸
3)SingleThreadExecutor(单线程池)
保证任务按顺序执行。
4)ScheduledThreadPool(定时任务线程池)
功能类似 Timer,但更强大。
六、线程池最佳实践(项目级建议)
✔ 使用 有界队列(ArrayBlockingQueue),避免 OOM
✔ 手动 new ThreadPoolExecutor,不用 Executors
✔ 根据任务类型决定线程数:
- CPU 密集:线程数 = CPU核数 + 1
- IO 密集:线程数 = CPU核数 * 2 或更多
✔ 记得设置线程名(threadFactory)方便排查
✔ 适当使用拒绝策略做流控 → CallerRunsPolicy
七、总结(背下来即可)
线程池的核心思想:复用线程,减少创建开销。
核心参数作用:
- corePoolSize:最小常驻线程数
- maximumPoolSize:最大线程数
- workQueue:任务排队的地方
- keepAliveTime:临时线程多久回收
- threadFactory:线程名字
- handler:拒绝策略
线程池执行流程:
核心线程 → 队列 → 临时线程 → 拒绝策略
下一篇: