Java 线程池七问七答:参数、执行流程、拒绝策略到 ThreadLocal 内存泄漏,面试必背

文章收录专栏:Java 核心原理全解:源码・并发・面试实战

系列文章:

Java 并发锁机制:从底层原理到锁升级,这一篇就够了

深入理解 Java 内存模型(JMM):从抽象规范到生产实践

Java 线程从生到死:创建三式、六态流转、中断协作与死锁活锁饥饿,一篇讲透

衔接引子 :上一篇讲线程 "怎么创建",但生产环境里我们几乎不直接 new Thread------ 线程创建销毁开销大、无法控制并发数。这一篇讲 JUC 里最核心的线程池 ,以及它带来的经典副作用 ThreadLocal 内存泄漏

1. 七大参数(面试必背)

corePoolSize 核心线程数、maximumPoolSize 最大线程数、keepAliveTime 空闲存活、TimeUnit 时间单位、BlockingQueue 任务队列、ThreadFactory 线程工厂、RejectedExecutionHandler 拒绝策略。

复制代码
ThreadPoolExecutor pool = new ThreadPoolExecutor(
    2,                                    // 核心线程数
    4,                                    // 最大线程数
    60, TimeUnit.SECONDS,                 // 非核心线程空闲 60s 回收
    new ArrayBlockingQueue<>(100),        // 有界队列
    r -> new Thread(r, "biz-pool-" + new AtomicInteger().incrementAndGet()), // 命名工厂
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);

2. 执行流程(精确到 execute)

提交任务 → ① 线程数 < corePoolSize → 建核心线程执行;② 否则尝试入队 offer();③ 入队失败且线程数 < maximumPoolSize → 建非核心线程执行;④ 否则执行拒绝策略。

顺序是 "核心 → 入队 → 非核心 → 拒绝",先判断核心再入队,这是最容易被面试官揪的细节。

3. 生命周期与关闭

状态机:RUNNING → SHUTDOWN → STOP → TIDYING → TERMINATED

  • shutdown():平缓关闭,不再收新任务,执行完队列已有任务
  • shutdownNow():立即关闭,interrupt 所有线程,返回未执行任务列表
  • beforeExecute/afterExecute 钩子可埋点;prestartAllCoreThreads() 预热核心线程

4. 四大拒绝策略

策略 行为 场景
AbortPolicy(默认) 抛 RejectedExecutionException 明确报错
CallerRunsPolicy 提交线程自己执行 降级限流
DiscardOldestPolicy 丢队列最旧,重提当前 可容忍丢任务
DiscardPolicy 静默丢弃 不推荐

生产常用自定义策略:记录日志 + 落库或 MQ 补偿。

5. 内置线程池风险(Executors 陷阱)

  • FixedThreadPool/SingleThreadPool:无界队列,任务堆积 OOM
  • CachedThreadPool:最大线程数无上限,可耗尽 CPU / 内存

生产规范:手动 new ThreadPoolExecutor + 有界队列 + 命名工厂 + 合理拒绝策略 + 按业务拆分。

6. ThreadLocal:原理与内存泄漏

原理:每个 Thread 持有一个 ThreadLocalMap,ThreadLocal 为 key、线程私有值为 value;哈希冲突用开放地址法(线性探测)

内存泄漏根因:key 是弱引用、GC 后变 null,但 value 是强引用无法回收;线程池复用线程时 value 长期挂留。

复制代码
ThreadLocal<User> tl = new ThreadLocal<>();
try {
    tl.set(new User("木雨"));
    // 业务逻辑
} finally {
    tl.remove(); // 必须在 finally 中清理
}

扩展InheritableThreadLocal 子线程创建时继承(线程池复用不传递);TransmittableThreadLocal(TTL,阿里)基于 "捕获→回放→恢复" 解决线程池上下文传递 ------ 微服务链路追踪必备。

7. 线程池死锁(生产高频)

同一个池内:任务 A 提交任务 B 并阻塞等待 B 的结果 ,核心线程被这类等待任务占满,B 永远排不进队 → 线程耗尽、任务堆积。解决:不同层级任务拆分线程池,禁止池内任务互相等待。

金句速记

线程池三问:队列满没满?线程到没到上限?拒绝策略认不认?ThreadLocal 一戒:用完全程 remove,不留垃圾在池里

相关推荐
艾莉丝努力练剑1 小时前
【AI大模型接入SDK】Gemini模型接入知识体系
java·开发语言·网络·人工智能·网络协议·学习·http
云运维笔记1 小时前
Zabbix 分布式监控搭建实战:基于 Proxy 实现 MySQL、Java、Nginx 监控
java·mysql·zabbix
zhanghaha13141 小时前
Python进阶教程:28_queue 队列模块 零基础超详细教程
java·开发语言·python
司小豆1 小时前
第七课:DeepSeek Harness 服务与依赖注入
java·服务器·开发语言·github·ai编程
ocean21032 小时前
2025-2026年计算机网络面试高频知识点洞察
计算机网络·面试·职场和发展·https·tcp·面试真题·秋招春招
许彰午2 小时前
24-MyBatisHelper与autoCount
java·低代码·架构
CRMEB系统商城2 小时前
汽车养护连锁的数字化底座CRMEB 多门店系统实战方案
java·开发语言·小程序·开源·汽车
学编程就要猛2 小时前
使用Spring AI配置聊天大模型实现人机交互(初阶)
java·spring ai·advisor·chatclient·chatmodel
代码不停2 小时前
子序列问题
java·算法