温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

ExecutorService怎处理异常

发布时间:2026-09-16 03:47:59 来源:亿速云 阅读:92 作者:小樊 栏目:编程语言

在 Java 中,ExecutorService 本身不会自动把任务里的异常抛出来,如果处理不当,异常很容易被“吞掉”。下面按常见场景系统说明如何处理异常。


一、任务类型不同,异常处理方式不同

1. Runnable 任务

executor.execute(() -> {
    throw new RuntimeException("error");
});

特点:

  • 异常不会抛给调用者
  • 默认只会在 未捕获异常处理器(ThreadGroup / Thread.setUncaughtExceptionHandler) 中体现

处理方式一:自己 try-catch

executor.execute(() -> {
    try {
        // 业务逻辑
    } catch (Exception e) {
        log.error("task error", e);
    }
});

处理方式二:自定义 ThreadFactory

ThreadFactory factory = r -> {
    Thread t = new Thread(r);
    t.setUncaughtExceptionHandler((thread, e) -> {
        log.error("thread error", e);
    });
    return t;
};

ExecutorService executor = Executors.newFixedThreadPool(2, factory);

2. Callable 任务(推荐)

Future<Integer> future = executor.submit(() -> {
    throw new RuntimeException("error");
});

关键点:

  • 异常被封装在 Future 中
  • 只有调用 future.get() 时才会抛出
try {
    future.get();
} catch (ExecutionException e) {
    Throwable cause = e.getCause(); // 真正的异常
    log.error("task failed", cause);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

✅ 这是最推荐的方式


二、使用 invokeAll / invokeAny

invokeAll

List<Future<T>> futures = executor.invokeAll(tasks);
for (Future<T> f : futures) {
    try {
        f.get();
    } catch (ExecutionException e) {
        // 处理异常
    }
}

invokeAny

  • 只要有一个成功就返回
  • 其他任务的异常被忽略(除非它们自己处理)

三、统一异常处理(进阶)

1. 包装任务(推荐)

static <T> Callable<T> wrap(Callable<T> task) {
    return () -> {
        try {
            return task.call();
        } catch (Exception e) {
            log.error("task error", e);
            throw e;
        }
    };
}

2. Spring 环境(@Async)

@Async
public void asyncTask() {
    throw new RuntimeException("error");
}

配置:

@Bean
public AsyncUncaughtExceptionHandler asyncUncaughtExceptionHandler() {
    return (ex, method, params) -> log.error("async error", ex);
}

四、常见坑总结 ⚠️

情况 结果
execute() 抛异常 被吞,除非有 UncaughtExceptionHandler
submit() 不调用 get() 异常永远不会知道
线程池满 + 拒绝策略 可能直接丢任务
异常被 catch 后不处理 等于没记录

五、最佳实践 ✅

✅ 优先使用 Callable + Future.get()
✅ 业务代码内部 try-catch
✅ 线程池统一异常日志
✅ 不建议依赖 UncaughtExceptionHandler 作为主手段


如果你愿意,我可以:

  • 给你一个 完整线程池模板
  • 或针对 Spring / Web / 定时任务 场景讲具体写法
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI
助
手