spring boot的@Async注解有什么坑?

Spring Boot 中 @Async 注解的常见坑(2025-2026 真实生产环境高频问题汇总,按严重程度排序)

排名坑的名称严重程度发生概率典型表现/后果解决/规避方案(推荐做法)
1同一个类内部方法调用不生效★★★★★★★★★★内部调用 @Async 方法,仍然同步执行1. 把 @Async 方法抽到另一个 Bean
2. 使用 AopContext.currentProxy()(不推荐)
3. 注入自己(Self Injection)最常用
2没有显式配置 Async 配置类★★★★½★★★★默认单线程池,线程池瞬间打满,所有异步任务排队甚至死锁必须自定义 ThreadPoolTaskExecutor 或使用 @EnableAsync + 自定义配置类
3线程池配置不当导致 OOM/任务堆积★★★★★★★★½队列无限增长 → OOM 或响应极慢合理设置核心/最大线程数 + 有界队列 + 拒绝策略(CallerRunsPolicy 较安全)
4@Async 方法抛异常调用方收不到★★★★★★★★异常被线程池吞掉,调用方完全感知不到1. 方法签名返回 CompletableFuture 并 get() 或 join()
2. 实现 AsyncUncaughtExceptionHandler
5事务失效(@Transactional + @Async)★★★★★★★½异步方法里的事务不生效或不回滚1. 异步方法不要加 @Transactional(推荐)
2. 或者把事务方法和异步方法分开
6使用默认的 SimpleAsyncTaskExecutor★★★½★★★★每次调用都 new 线程,无线程复用,性能极差坚决不要使用默认,必须自定义线程池
7返回 void 的异步方法异常丢失★★★½★★★void 方法抛异常完全无声无息实现 AsyncUncaughtExceptionHandler 或改用返回 Future 类型
8线程上下文丢失(MDC、RequestContext、TenantId 等)★★★★★★½日志 traceId 丢失、租户信息丢失、安全上下文丢失使用 TaskDecorator 包装 Runnable,复制上下文
9@Async 用在静态方法/私有方法★★★★★½压根不生效(AOP 无法代理)只能用在 public 非静态方法上
10大量 @Async 导致线程饥饿★★½★★★核心业务线程池被异步任务占满,导致主流程卡死1. 给不同业务类型使用不同线程池
2. 控制异步任务总量

目前生产环境最推荐的安全写法模板(2025-2026 共识)

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(8);           // 根据机器核数调整
        executor.setMaxPoolSize(32);
        executor.setQueueCapacity(500);        // 有界队列
        executor.setThreadNamePrefix("Async-");
        // 拒绝策略:由调用者线程执行(防止任务丢失)
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }

    // 捕获 void 方法的未捕获异常
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -> {
            log.error("异步方法异常!method={}, params={}", method.getName(), params, ex);
            // 可选:发送告警
        };
    }
}

总结:最容易踩的 3 个大坑(面试/生产必背)

  1. 同一个类里调用 @Async 方法不生效 → 这是 90% 以上初学者都会踩的坑
  2. 没有自定义线程池 → 默认单线程或无限线程,迟早出事
  3. 异常感知不到 + 上下文丢失 → 日志断层、问题定位困难、生产事故高发

一句话结论:

@Async 看着简单,用好了是性能利器,用不好就是定时炸弹。
生产环境用 @Async 的第一原则:必须自定义线程池 + 必须把异步方法抽到独立的 @Service 类里 + 必须想好异常怎么感知。

如果你目前项目里已经在用 @Async,建议对照上面表格检查一遍配置和使用方式,能省很多半夜被叫醒的麻烦~ 😅

文章已创建 3855

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部