在 Java 中,ExecutorService 本身不会自动把任务中的异常抛出到主线程,如果处理不当,异常很容易被“吞掉”。下面按使用方式系统说明如何处理异常。
execute(Runnable)executor.execute(() -> {
throw new RuntimeException("error");
});
✅ 异常会:
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
System.err.println("Thread " + t.getName() + " error: " + e);
});
或自定义 ThreadFactory:
ThreadFactory factory = r -> {
Thread t = new Thread(r);
t.setUncaughtExceptionHandler((t1, e) -> System.err.println(e));
return t;
};
submit(Runnable) / submit(Callable)Future<?> future = executor.submit(() -> {
throw new RuntimeException("error");
});
❌ 异常不会立即抛出
✅ 异常被封装在 Future 中
try {
future.get(); // 会抛出 ExecutionException
} catch (ExecutionException e) {
Throwable cause = e.getCause(); // 真正的异常
e.printStackTrace();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
⚠️ 如果不调用 get(),异常会被吞掉。
Callable + Future最清晰、可控
Future<String> f = executor.submit(() -> {
if (true) throw new RuntimeException("fail");
return "ok";
});
try {
f.get();
} catch (ExecutionException e) {
log.error("task failed", e.getCause());
}
executor.execute(() -> {
try {
business();
} catch (Exception e) {
log.error("task error", e);
}
});
适合:
ThreadPoolExecutor 重写 afterExecutenew ThreadPoolExecutor(...) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
if (t != null) {
log.error("task error", t);
}
if (r instanceof Future<?>) {
try {
((Future<?>) r).get();
} catch (ExecutionException e) {
log.error("future error", e.getCause());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
};
✅ 统一捕获 execute 和 submit 的异常
@Async
public void run() {
throw new RuntimeException("error");
}
✅ 使用:
@Bean
public AsyncUncaughtExceptionHandler asyncUncaughtExceptionHandler() {
return (ex, method, params) -> log.error("async error", ex);
}
| 提交方式 | 异常是否抛出 | 如何处理 |
|---|---|---|
| execute | 否 | UncaughtExceptionHandler |
| submit | 否(延迟) | future.get() |
| Callable | 否(延迟) | future.get() |
| afterExecute | 是 | 统一处理 |
| Spring @Async | 否 | AsyncUncaughtExceptionHandler |
如果你有具体场景(比如:定时任务 / 批量任务 / 线程池参数),我可以给你一个可直接用的模板代码。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。