Java 执行器与线程池
Executor 框架如何提交任务、管理线程池与关闭:队列、拒绝策略与生命周期。
#type / concept
#status / growing
#tech / dev
#resource / java
[!info] 关联笔记
Java 执行器与线程池
这个概念为什么出现
直接 new Thread 无法统一限流、复用与关闭。ExecutorService 把任务提交与执行策略分离:固定/弹性线程池、队列、拒绝策略与 Future 结果。
[!abstract] 一句话理解 线程池复用工作线程执行提交的任务;必须正确配置队列与拒绝策略,并在关闭时
shutdown/awaitTermination。
最小可运行示例
场景:图片缩略图任务有限并发
import java.util.concurrent.*;
public class ThumbPool {
public static void main(String[] args) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(2, r -> {
Thread t = new Thread(r);
t.setName("thumb-" + t.getId());
return t;
});
try {
Future<String> f = pool.submit(() -> {
// 模拟生成缩略图
return "thumb-ok";
});
System.out.println(f.get(1, TimeUnit.SECONDS));
} finally {
pool.shutdown();
pool.awaitTermination(1, TimeUnit.SECONDS);
}
}
}
建议运行:
javac ThumbPool.java && java ThumbPool
期望输出:
thumb-ok
结合场景再看三个关注点
- submit 返回 Future 可取结果/异常。
- shutdown 在 finally,防泄漏。
- 工厂方法要懂默认队列:
newFixedThreadPool用无界队列,压力下可能 OOM。
核心概念与准确模型
1. 关键角色
Executor/ExecutorServiceThreadPoolExecutor核心实现- 工作队列、核心/最大线程、拒绝策略
2. 拒绝策略
Abort / CallerRuns / Discard / DiscardOldest 等
3. 生命周期
shutdown 温和停 → awaitTermination → 必要时 shutdownNow
4. Callable vs Runnable
- Callable 有返回值且可抛受检异常
边界情况与反直觉行为
get()无限等。- 池线程吞掉异常(Future 中持有)。
- 错误的最大线程 + 无界队列 = 实际不扩容。
常见误区
[!warning] 常见误区:Executors 工厂无脑用 生产常显式
ThreadPoolExecutor并命名、监控队列长度。
工程实践
- 按业务隔离池(CPU 密集 vs IO)。
- 监控活跃线程、队列、拒绝次数。
- 请求上下文传递(MDC)要包装任务。
- 与虚拟线程:大量阻塞任务可用新模型(见虚拟线程篇)。
本节总结
- 池化执行是默认工程姿势
- 配置队列/拒绝/关闭
- Future 承载结果与错误
自测题
- shutdown 与 shutdownNow 区别?
- 无界队列的主要风险?
参考答案
- 前者不再接新任务并执行完在途;后者尝试中断在途并返回等待任务。
- 任务堆积导致内存膨胀,线程数可能不按预期增长。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Executor interface | API | 执行器 |
| ThreadPoolExecutor | API | 池参数 |