java
import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) {
// ========== 1. 创建线程池 ==========
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // corePoolSize: 核心线程数
4, // maximumPoolSize: 最大线程数
60L, // keepAliveTime: 非核心线程空闲存活时间
TimeUnit.SECONDS, // 时间单位
new ArrayBlockingQueue<>(3), // workQueue: 任务队列,容量3
new ThreadPoolExecutor.CallerRunsPolicy() // handler: 拒绝策略
);
// ========== 2. 提交任务 ==========
System.out.println("=== 开始提交10个任务 ===\n");
for (int i = 1; i <= 10; i++) {
int taskId = i;
executor.submit(() -> {
// 模拟耗时任务
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("【任务%d】由线程【%s】执行\n",
taskId, Thread.currentThread().getName());
});
}
// ========== 3. 关闭线程池 ==========
executor.shutdown();
try {
// 等待所有任务完成
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
System.out.println("\n=== 所有任务执行完成 ===");
}
}
七个核心参数


有四种拒绝策略
// ① 抛出异常(默认) new ThreadPoolExecutor.AbortPolicy() // ② 丢弃任务,不抛异常 new ThreadPoolExecutor.DiscardPolicy() // ③ 丢弃最老的任务,执行新任务 new ThreadPoolExecutor.DiscardOldestPolicy() // ④ 由调用线程执行(推荐用于重要任务) new ThreadPoolExecutor.CallerRunsPolicy()
线性池的面试考点
【基础类】
-
为什么要用线程池?
-
线程池的核心参数有哪些?
-
线程池的工作流程是什么?
-
4种拒绝策略的区别?
【进阶类】
-
为什么不建议用Executors创建线程池?
-
如何配置线程池参数?
-
如何监控线程池?
-
如何优雅关闭线程池?
【源码类】
-
线程池如何复用线程?
-
Worker的作用是什么?
-
线程池的5种状态?
-
AQS在线程池中的作用?
【实战类】 13. 生产环境如何配置线程池?
-
线程池OOM怎么排查?
-
任务执行慢怎么处理?
-
如何自定义拒绝策略?
🧵 Java线程池 - 16道面试真题速记版
【基础类】
1️⃣ 为什么要用线程池?
✅ 降低资源消耗:复用线程,减少创建/销毁开销
✅ 提高响应速度:任务到达无需等待线程创建
✅ 提高可管理性:统一分配、调优和监控
✅ 控制并发量:防止过多线程导致系统崩溃
2️⃣ 线程池的核心参数有哪些?
① corePoolSize - 核心线程数
② maximumPoolSize - 最大线程数
③ keepAliveTime - 非核心线程空闲存活时间
④ unit - 时间单位
⑤ workQueue - 任务队列
⑥ threadFactory - 线程工厂
⑦ handler - 拒绝策略
3️⃣ 线程池的工作流程是什么?
1. 提交任务 → 核心线程未满 → 创建核心线程执行
2. 核心线程已满 → 任务放入队列
3. 队列已满 → 创建非核心线程执行
4. 最大线程已满 → 触发拒绝策略
4️⃣ 4种拒绝策略的区别?
| 策略 | 行为 | 场景 |
|---|---|---|
| AbortPolicy | 抛异常(默认) | 不允许任务丢失 |
| DiscardPolicy | 静默丢弃 | 任务可丢失(如日志) |
| DiscardOldestPolicy | 丢弃最老任务 | 新任务更重要 |
| CallerRunsPolicy | 调用者线程执行 | 重要任务,需降级 |
【进阶类】
5️⃣ 为什么不建议用Executors创建线程池?
❌ FixedThreadPool/SingleThreadExecutor:
队列是LinkedBlockingQueue,容量Integer.MAX_VALUE,可能OOM
❌ CachedThreadPool:
最大线程数Integer.MAX_VALUE,可能创建过多线程导致OOM
✅ 推荐:手动创建ThreadPoolExecutor,设置有界队列
6️⃣ 如何配置线程池参数?
CPU密集型:核心线程数 = CPU核数 + 1
IO密集型:核心线程数 = CPU核数 × 2
队列大小:根据业务峰值和缓冲时间计算
最大线程数:核心线程数 + 缓冲线程
keepAliveTime:60秒左右
拒绝策略:根据业务重要性选择
7️⃣ 如何监控线程池?
// 关键指标
executor.getPoolSize() // 当前线程数
executor.getActiveCount() // 活跃线程数
executor.getQueue().size() // 队列大小
executor.getCompletedTaskCount() // 已完成任务数
// 监控方案
1. 定期打印日志
2. 集成Prometheus + Grafana
3. 使用阿里Druid等自带监控的线程池
8️⃣ 如何优雅关闭线程池?
// 1. 停止接收新任务
executor.shutdown();
// 2. 等待任务完成(设置超时)
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
// 3. 超时后强制关闭
executor.shutdownNow();
}
// 4. 处理未完成任务(持久化等)
【源码类】
9️⃣ 线程池如何复用线程?
Worker线程执行完一个任务后,不会直接退出,
而是循环调用getTask()从队列获取新任务,
实现线程复用,减少线程创建/销毁开销
🔟 Worker的作用是什么?
Worker是线程池的工作单元,继承AQS:
- 封装实际执行的Thread
- 保存第一个任务firstTask
- 用独占锁保护线程执行状态
- 防止任务执行中被中断
1️⃣1️⃣ 线程池的5种状态?
RUNNING - 接受新任务,处理队列任务
SHUTDOWN - 不接受新任务,处理队列任务
STOP - 不接受新任务,不处理队列,中断进行中任务
TIDYING - 所有任务终止,准备执行terminated()
TERMINATED - 终止完成
1️⃣2️⃣ AQS在线程池中的作用?
Worker继承AQS,使用独占锁:
- 保护线程执行状态,防止并发修改
- 判断线程是否正在执行任务
- 支持中断控制和线程状态管理
【实战类】
1️⃣3️⃣ 生产环境如何配置线程池?
1. 手动创建ThreadPoolExecutor(不用Executors)
2. 设置有界队列(如ArrayBlockingQueue)
3. 根据任务类型配置线程数(CPU/IO密集型)
4. 设置合理的keepAliveTime
5. 选择合适的拒绝策略
6. 自定义线程工厂(命名、守护线程等)
7. 集成监控和告警
1️⃣4️⃣ 线程池OOM怎么排查?
1. 检查队列是否无界(LinkedBlockingQueue)
2. 检查最大线程数是否过大
3. 查看任务是否阻塞或执行过慢
4. 使用jmap查看堆内存
5. 使用jstack查看线程堆栈
6. 检查GC日志和内存泄漏
解决:设置有界队列、限制最大线程数、优化任务
1️⃣5️⃣ 任务执行慢怎么处理?
1. 查看活跃线程数和队列大小(监控指标)
2. 使用jstack查看线程堆栈,检查是否死锁
3. 检查GC情况,是否频繁Full GC
4. 检查数据库/网络等外部依赖
5. 适当增加线程数或优化任务逻辑
6. 考虑任务拆分或异步处理
1️⃣6️⃣ 如何自定义拒绝策略?
// 实现RejectedExecutionHandler接口
class MyRejectHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 1. 记录日志
log.warn("任务被拒绝: {}", r);
// 2. 持久化到数据库/消息队列
// saveToMQ(r);
// 3. 发送告警
// sendAlert();
}
}
// 使用
new ThreadPoolExecutor(..., new MyRejectHandler());
📋 速记口诀
线程池,七参数,核心最大队列满
拒绝策略有四种,生产不用Executors
CPU型,N+1,IO型,N乘2
监控关闭要做好,源码Worker要理解