线程池(ThreadPoolExecutor)
ThreadPoolExecutor 执行流程(面试必问的那条线)。
现在的基础已经够了:
- 知道 Runnable 是任务
- 知道 Thread 是线程
- 知道 Thread 和 Runnable 的关系
- 知道线程 = 工人,任务 = 活
- 已经理解为什么不能一个任务一个 Thread
- 已经明白线程池才是现代工程的正确做法
现在正是进入线程池主线流程的最佳时机。
🎯 线程池执行流程(ThreadPoolExecutor 绝对核心)
明天面试 90% 会遇到这个:
“线程池接到任务后是怎么执行的?
请你把流程讲一遍。”
你讲得好的话,就算别的 Java 基础弱一点,他们也会觉得你“理解力强”、“成长很快”。
所以我们直接开始。
🌟 Part 1:线程池核心组成(最简单的解释)
线程池由三部分组成:
① 核心线程 corePoolSize(永远在线的工人)
② 工作队列 workQueue(任务排队的地方)
③ 非核心线程 maximumPoolSize(临时工)
你只要记住这三个角色,流程就完全不难理解。
🌟 Part 2:线程池处理任务的 4 个阶段(超级重要)
当你调用:
executor.execute(task);
线程池会按顺序执行 4 个步骤:
① 如果核心线程没满 → 创建核心线程来执行任务
流程:
核心线程还没达到 corePoolSize?
是 → 创建新线程执行任务(直接执行,不排队)
核心线程永远优先执行任务。
② 核心线程满了 → 把任务放进队列
队列没满?
是 → 放进 workQueue 排队
这是大部分企业自己写任务调度、日志处理时最常见的状态。
③ 队列满了 → 创建临时线程(非核心线程)
队列满了吗?
是 → 创建非核心线程执行任务
临时线程数量最多到 maximumPoolSize。
④ 队列满 + 非核心线程也满 → 触发拒绝策略
如果临时线程达到 maximumPoolSize:
→ 拒绝策略 handler 拒绝任务
这就是为什么线程池可以防止系统崩溃 —— 它会拒绝任务,而不是无限创建线程。
这在后端面试是大加分项。
🌟 Part 3:告诉你为什么 ThreadPoolExecutor 这么设计(理解深度加分)
它保证:
- 优先让核心线程执行全部任务(高性能)
- 队列控制系统稳定性(不会爆线程)
- 临时线程处理突发流量(提高吞吐)
- 拒绝策略防止压垮服务器
这个流程是顶级 Java 工程师经常讲的点。
你现在学会了,面试官对你印象会非常好。
当面试官问:
“线程池接收到任务后怎么执行?”
你可以这样答:
⭐「面试官听了会点头的版本」:
线程池执行任务是一个四步流程:
- 如果核心线程未满,直接创建核心线程执行任务
- 如果核心线程满了,把任务加入阻塞队列
- 如果队列也满了,创建非核心线程执行任务
- 如果非核心线程达到 maximumPoolSize,触发拒绝策略
接下来我们把 线程池剩下的 3 大模块补全:
🌟 第一部分:线程池七大核心参数(必须会、必须能讲)
构造方法:
ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler
)
我用你最能理解的方式(工人 + 任务队列)讲:
① corePoolSize(核心线程数)🔥
线程池启动后,最少会保留这么多线程,
即使这些线程空闲,也不会销毁。
核心线程 = 正式工人。
特点:
- 有任务直接执行
- 没任务也保持在线(默认)
👉 这是线程池最重要的参数之一。
② maximumPoolSize(最大线程数)🔥🔥
当任务很多:
- 核心线程忙
- 队列塞满
才会创建 临时线程(非核心线程)
最多创建到 maximumPoolSize 数量。
临时线程 = 临时工(高峰支援)。
③ keepAliveTime(非核心线程空闲多久被销毁)
临时线程干完活后,如果闲太久,就被销毁。
默认:只对非核心线程有效。
④ unit(时间单位)
秒 / 毫秒 / 分钟。
⑤ workQueue(阻塞队列)🔥🔥🔥
当核心线程忙时,任务进入队列排队。
三类最常考:
✔ ArrayBlockingQueue(有界队列)
→ 控制队列长度(推荐用于生产)
→ 会触发 maximumPoolSize
✔ LinkedBlockingQueue(无界队列)
→ 危险!任务无限堆积(可能 OOM)
→ maximumPoolSize 形同虚设
✔ SynchronousQueue(不排队)
→ 每个任务必须有线程执行
→ 用于 cachedThreadPool(无限扩容!)
你以后做数据平台、日志处理,一定要选对队列。
⑥ threadFactory(线程工厂)
给线程命名,方便排查问题。
例如:
new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(r, "etl-worker-" + ID++);
}
}
⑦ handler(拒绝策略)🔥🔥
当:
- 核心线程满
- 队列满
- 最大线程数也满
就触发拒绝策略。
下面单独讲。
🌟 第二部分:线程池四大拒绝策略(面试高频)
默认的是第一个。
① AbortPolicy(默认)——抛异常 ❗
抛出 RejectedExecutionException。
② DiscardPolicy —— 直接丢任务
不抛异常,不执行。
③ DiscardOldestPolicy —— 丢掉队列头任务
把队列里的最旧任务丢掉,让新的任务进来。
慎用!
④ CallerRunsPolicy —— 任务由提交者线程执行
execute() 是谁调用,它就在哪个线程执行。
比如你在 main() 调用:
→ main 线程自己执行任务。
好处:限流
坏处:调用线程被拖慢
🌟 面试官常问你什么?
“你们项目里拒绝策略选择哪种?为什么?”
你可以回答:
✔ 对 ETL / 数据清洗任务:
我会用 CallerRunsPolicy,让系统在压力过大时自动限流,避免任务丢失。
✔ 对日志系统:
用 DiscardPolicy,一部分日志丢了也没事。
🌟 第三部分:为什么不推荐 Executors?(面试必问)
面试官:
“为什么不推荐 Executors.newFixedThreadPool ?”
你说一句就赢了:
⭐ newFixedThreadPool 使用的是 LinkedBlockingQueue(无界队列),可能 OOM。
面试官:
“为什么不推荐 CachedThreadPool?”
你说:
⭐ CachedThreadPool 使用 SynchronousQueue,线程数不受限制,可能无限创建线程耗尽系统资源。
面试官:
“那该怎么创建线程池?”
你说:
⭐ 使用 ThreadPoolExecutor 手动指定队列、核心线程、最大线程数,行为可控、可预测。
🌟 线程池最后部分:最佳实践(让你显得很专业)
✔ (1)设置合理的核心线程数
通常 = CPU 核心数
✔ (2)队列一定要用有界队列(防止 OOM)
✔ (3)拒绝策略必须手动选择
✔ (4)线程名字必须指定,方便排查问题
✔ (5)shutdown() 和 shutdownNow() 要知道区别
🌟 你的线程池知识已经完整了!
你现在具备:
| 能力点 | 是否掌握? |
|---|---|
| 线程池执行流程 | ✔ 完成 |
| 七大参数 | ✔ 完成 |
| 队列分类 | ✔ 完成 |
| 拒绝策略 | ✔ 完成 |
| Executors 为什么不用 | ✔ 完成 |
| Runnable / Thread / Callable 关系 | ✔ 完成 |
| ThreadPoolExecutor 创建方式 | ✔ 完成 |
这已经达到 腾讯后端面试可用级别,非常稳!
❤️ 下一步(我建议你继续补):
明天面试预计还会问:
🔥 1. volatile / CAS (已会)
🔥 2. Java 内存结构 (已会)
🔥 3. Spring IOC / AOP(要讲)
🔥 4. SQL 复杂查询(要讲)
🔥 5. Pandas 基础(要讲)
🔥 6. ETL 思路(要讲)
你现在可以选一个模块继续:
👉 “讲 Spring IOC / AOP”
👉 “讲 SQL 索引和 join 优化”
👉 “讲 Pandas 20 分钟速成”
👉 “讲 ETL 设计流程”
你选一个,我继续手把手带你冲刺。
Top comments (0)