DEV Community

Liu yu
Liu yu

Posted on

JAVA多线程

线程池(ThreadPoolExecutor)

ThreadPoolExecutor 执行流程(面试必问的那条线)。

现在的基础已经够了:

  • 知道 Runnable 是任务
  • 知道 Thread 是线程
  • 知道 Thread 和 Runnable 的关系
  • 知道线程 = 工人,任务 = 活
  • 已经理解为什么不能一个任务一个 Thread
  • 已经明白线程池才是现代工程的正确做法

现在正是进入线程池主线流程的最佳时机。


🎯 线程池执行流程(ThreadPoolExecutor 绝对核心)

明天面试 90% 会遇到这个:

“线程池接到任务后是怎么执行的?
请你把流程讲一遍。”

你讲得好的话,就算别的 Java 基础弱一点,他们也会觉得你“理解力强”、“成长很快”。

所以我们直接开始。


🌟 Part 1:线程池核心组成(最简单的解释)

线程池由三部分组成:

① 核心线程 corePoolSize(永远在线的工人)
② 工作队列 workQueue(任务排队的地方)
③ 非核心线程 maximumPoolSize(临时工)
Enter fullscreen mode Exit fullscreen mode

你只要记住这三个角色,流程就完全不难理解。


🌟 Part 2:线程池处理任务的 4 个阶段(超级重要)

当你调用:

executor.execute(task);
Enter fullscreen mode Exit fullscreen mode

线程池会按顺序执行 4 个步骤


① 如果核心线程没满 → 创建核心线程来执行任务

流程:

核心线程还没达到 corePoolSize?
    是 → 创建新线程执行任务(直接执行,不排队)
Enter fullscreen mode Exit fullscreen mode

核心线程永远优先执行任务。


② 核心线程满了 → 把任务放进队列

队列没满?
    是 → 放进 workQueue 排队
Enter fullscreen mode Exit fullscreen mode

这是大部分企业自己写任务调度、日志处理时最常见的状态。


③ 队列满了 → 创建临时线程(非核心线程)

队列满了吗?
    是 → 创建非核心线程执行任务
Enter fullscreen mode Exit fullscreen mode

临时线程数量最多到 maximumPoolSize


④ 队列满 + 非核心线程也满 → 触发拒绝策略

如果临时线程达到 maximumPoolSize:
    → 拒绝策略 handler 拒绝任务
Enter fullscreen mode Exit fullscreen mode

这就是为什么线程池可以防止系统崩溃 —— 它会拒绝任务,而不是无限创建线程。

这在后端面试是大加分项。


🌟 Part 3:告诉你为什么 ThreadPoolExecutor 这么设计(理解深度加分)

它保证:

  • 优先让核心线程执行全部任务(高性能)
  • 队列控制系统稳定性(不会爆线程)
  • 临时线程处理突发流量(提高吞吐)
  • 拒绝策略防止压垮服务器

这个流程是顶级 Java 工程师经常讲的点。

你现在学会了,面试官对你印象会非常好。


当面试官问:

“线程池接收到任务后怎么执行?”

你可以这样答:


⭐「面试官听了会点头的版本」:

线程池执行任务是一个四步流程:

  1. 如果核心线程未满,直接创建核心线程执行任务
  2. 如果核心线程满了,把任务加入阻塞队列
  3. 如果队列也满了,创建非核心线程执行任务
  4. 如果非核心线程达到 maximumPoolSize,触发拒绝策略

接下来我们把 线程池剩下的 3 大模块补全:


🌟 第一部分:线程池七大核心参数(必须会、必须能讲)

构造方法:

ThreadPoolExecutor(
    int corePoolSize,        
    int maximumPoolSize,     
    long keepAliveTime,      
    TimeUnit unit,           
    BlockingQueue<Runnable> workQueue,  
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler 
)
Enter fullscreen mode Exit fullscreen mode

我用你最能理解的方式(工人 + 任务队列)讲:


① 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++);
    }
}
Enter fullscreen mode Exit fullscreen mode

⑦ 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)