ExecutorService常见异常
ExecutorService 是 Java 并发包(java.util.concurrent)中用于管理线程池的核心接口。在使用它的过程中,常见异常主要集中在任务提交、线程池关闭、任务执行、配置不合理等方面。下面按使用场景系统梳理常见异常及其原因和处理建议。
一、任务执行过程中的异常
1. NullPointerException
出现场景
executorService.submit(null);
原因
- 提交的任务为
null - 或
Callable/Runnable内部引用了空对象
解决
- 提交前校验任务非空
- 在任务内部做好空值判断
2. RuntimeException / Error
出现场景
executorService.submit(() -> {
throw new RuntimeException("error");
});
特点
- 不会直接抛出
- 只会在调用
Future.get()时抛出
Future> f = executorService.submit(task);
f.get(); // 这里抛 ExecutionException
本质
- 被包装为
ExecutionException
✅ 建议
try {
future.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
}
二、与 Future.get() 相关的异常
3. ExecutionException
含义
- 任务执行过程中抛出的异常
示例
Future f = executorService.submit(() -> 1 / 0);
f.get(); // ArithmeticException 被包装
4. InterruptedException
含义
- 当前线程在等待
future.get()时被中断
示例
try {
future.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
}
✅ 最佳实践
- 捕获后不要忽略中断
- 重新设置中断标志
5. TimeoutException
含义
get(long timeout, TimeUnit unit)超时
示例
future.get(1, TimeUnit.SECONDS);
解决
- 增加超时时间
- 检查任务是否死循环或阻塞
三、线程池关闭相关异常
6. RejectedExecutionException(最常见)
含义
- 线程池已关闭或任务队列已满,拒绝新任务
出现场景
executorService.shutdown();
executorService.submit(task); // 抛异常
或:
- 队列满 + 线程数已达 max
- 使用
AbortPolicy(默认)
常见触发条件
- 调用
shutdown()/shutdownNow()后继续提交任务 - 队列容量过小
- 任务提交速度远大于消费速度
✅ 解决方案
- 使用
CallerRunsPolicy - 合理设置队列大小
- 提交前判断状态
if (!executorService.isShutdown()) {
executorService.submit(task);
}
四、配置不合理导致的异常
7. IllegalArgumentException
出现场景
Executors.newFixedThreadPool(-1); // 或自定义 ThreadPoolExecutor
原因
- 核心线程数、最大线程数、队列容量非法
✅ 解决
- 校验参数合法性
五、线程池资源耗尽问题(非异常但致命)
8. 线程池“假死” / OOM
表现
- 不抛异常
- 任务不再执行
- 系统卡死
原因
- 使用
newCachedThreadPool()无限制创建线程 - 使用
LinkedBlockingQueue()无界队列 - 任务堆积
✅ 建议
- 使用
ThreadPoolExecutor明确参数 - 使用有界队列
- 自定义拒绝策略
六、常见异常速查表
| 异常 | 触发原因 | 是否常见 |
|---|---|---|
RejectedExecutionException |
线程池关闭 / 满 | ⭐⭐⭐⭐⭐ |
ExecutionException |
任务执行异常 | ⭐⭐⭐⭐ |
InterruptedException |
等待时被中断 | ⭐⭐⭐ |
TimeoutException |
超时未返回 | ⭐⭐⭐ |
NullPointerException |
提交 null 任务 | ⭐⭐ |
IllegalArgumentException |
参数非法 | ⭐ |
七、最佳实践总结
✅ 推荐写法
ExecutorService executor = new ThreadPoolExecutor(
2,
4,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
new ThreadPoolExecutor.CallerRunsPolicy()
);
✅ 任务异常处理
submit→future.get()execute→ 自定义ThreadFactory+UncaughtExceptionHandler
如果你愿意,我可以:
- 结合你具体代码分析异常
- 对比
submit()和execute()的异常处理差异 - 讲清 拒绝策略 + 队列选型 的最佳实践