Spring进阶特性 异步处理(@Async)

Spring 异步处理(@Async)是真正决定你的系统能不能“扛住并发”的进阶特性之一。
99% 的初学者只会写个 @Async 就以为完事了,结果生产一并发就崩。
下面给你 2025 年最新、最地道的 Spring Boot 3.x(JDK 17+)异步全套最佳实践,直接可用于银行、电商、互联网大厂核心系统。

1. 核心对比总览(2025 最新版)

方案是否真正异步是否支持返回值是否支持异常捕获是否支持线程池隔离推荐场景
直接 @Async(不配置)同步(假异步)不支持抛不出来永远不要用!
@Async + 默认线程池真异步不支持吃掉异常小项目、日志打印
自定义线程池 + @Async真异步支持(Future/CompletableFuture)可捕获支持90% 生产项目
ThreadPoolTaskExecutor + 队列监控真异步支持支持支持大中型项目
异步 + 分布式调用追踪(MDC + Async)真异步支持支持支持微服务项目
Spring Boot 3 + Virtual Threads(JDK 21)百万级并发支持支持内置2025 年新趋势(超高并发系统

2. 正确打开方式(99% 的人第一步就错了)

@EnableAsync                     // 主类一定要加!!
@Configuration
public class AsyncConfig {

    // 强烈推荐:每个业务一个线程池,彻底隔离
    @Bean("orderAsyncExecutor")
    public ThreadPoolTaskExecutor orderExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(8);
        executor.setMaxPoolSize(32);
        executor.setQueueCapacity(1000);           // 关键:队列满了要拒绝!
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("order-async-");

        // 生产必备:拒绝策略用 CallerRunsPolicy(打满时让调用线程自己执行,防止雪崩)
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        // 可选:优雅关闭
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }

    @Bean("mailAsyncExecutor")
    public ThreadPoolTaskExecutor mailExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("mail-async-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

3. 使用方式大全

@Service
@RequiredArgsConstructor
public class OrderService {

    // 1. 无返回值(最常用:发邮件、记录日志、埋点)
    @Async("mailAsyncExecutor")                     // 指定线程池!!
    public void sendOrderConfirmEmail(Long orderId) {
        try {
            // 模拟耗时
            Thread.sleep(3000);
            log.info("邮件已发送,订单号:{}", orderId);
        } catch (Exception e) {
            log.error("发送邮件失败", e);               // 异常不会抛到主线程!
        }
    }

    // 2. 有返回值(Future)
    @Async("orderAsyncExecutor")
    public CompletableFuture<String> generateReport(Long orderId) {
        try {
            Thread.sleep(5000);
            return CompletableFuture.completedFuture("报告生成成功");
        } catch (Exception e) {
            return CompletableFuture.failedFuture(e);
        }
    }

    // 3. 有返回值 + 异常传播(推荐)
    @Async("orderAsyncExecutor")
    public CompletableFuture<UserDTO> loadUserDetail(Long userId) {
        return CompletableFuture.supplyAsync(() -> {
            // 这里抛异常会自动包装到 CompletableFuture
            if (userId == 666) throw new BusinessException("用户不存在");
            return new UserDTO(userId, "张三");
        }, taskExecutor); // 可指定线程池
    }
}

Controller 调用方式:

@GetMapping("/order/create")
public R<Void> createOrder() {
    Long orderId = 12345L;

    // 火力全开异步(完全不阻塞主线程)
    orderService.sendOrderConfirmEmail(orderId);
    orderService.sendSms(orderId);
    orderService.recordLog(orderId);
    orderService.pushToDataWarehouse(orderId);

    return R.ok("订单创建成功,主流程已完成,通知类任务异步处理中");
}

// 需要返回值时
@GetMapping("/report")
public CompletableFuture<R<String>> getReport() {
    return orderService.generateReport(123L)
        .thenApply(R::ok)
        .exceptionally(e -> R.error(e.getMessage()));
}

4. 生产级进阶技巧(大厂标配)

1. 异步异常统一捕获(否则异常被吞掉!)

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(Throwable ex, Method method, Object... params) {
        log.error("异步任务异常:方法={}, 参数={}, 异常={}",
                  method.getName(), Arrays.toString(params), ex.getMessage(), ex);
        // 可推送到告警系统
        // DingTalkUtil.send("异步任务崩溃啦!", ex);
    }
}

// 在配置类中注册
@Bean
public AsyncConfigurer asyncConfigurer() {
    return new AsyncConfigurer() {
        @Override
        public Executor getAsyncExecutor() {
            return orderExecutor();
        }

        @Override
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
            return new AsyncExceptionHandler();
        }
    };
}

2. 异步方法内继续使用 MDC 链路追踪(微服务必备)

@Async("orderAsyncExecutor")
public void processOrder(Long orderId) {
    // 关键:手动传递 MDC
    Map<String, String> contextMap = MDC.getCopyOfContextMap();
    CompletableFuture.runAsync(() -> {
        if (contextMap != null) {
            MDC.setContextMap(contextMap);
        }
        try {
            log.info("开始处理订单:{}", orderId);
            // 业务代码...
        } finally {
            MDC.clear();
        }
    });
}

3. 2025 最新:虚拟线程(Virtual Threads)——百万级并发杀器

# application.yml (Spring Boot 3.2+ + JDK 21)
spring:
  threads:
    virtual:
      enabled: true        # 一键开启虚拟线程,所有 @Async 自动用虚拟线程!

开启后你甚至不需要配置线程池,Spring 自动把所有 @Async 换成虚拟线程,QPS 轻松 10w+。

5. 常见坑 & 终极建议

坑点解决方案
同一个类里调用 @Async 方法不生效必须通过 Spring 代理调用(注入自己或用 ApplicationContext 手动获取代理)
异常被吞掉,线上查不到原因实现 AsyncUncaughtExceptionHandler
线程池打满导致主线程卡死队列满了用 CallerRunsPolicy,让调用线程自己干活
异步方法返回 void 时无法感知执行结果改用 CompletableFuture<Void>
异步任务太多导致 OOM限制队列长度 + 监控 + 熔断

6. 推荐架构(2025 真实生产实践)

项目规模推荐方案
小项目@EnableAsync + 默认线程池(SimpleAsyncTaskExecutor)
中大型项目多个自定义 ThreadPoolTaskExecutor + 异常处理器 + MDC 传递
高并发互联网项目开启 spring.threads.virtual.enabled=true(JDK 21)
银行/金融核心系统自定义线程池 + 队列监控 + 告警 + 降级 + CallerRunsPolicy

需要我直接给你一个完整的生产级异步模板项目吗?包含:

  • 6 个业务隔离线程池
  • 统一异常处理 + 告警
  • MDC 自动传递
  • 异步任务监控指标(Micrometer + Prometheus)
  • 虚拟线程一键开关

直接说一声,我发你 GitHub 地址,拿来即用。

文章已创建 3070

发表回复

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

相关文章

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

返回顶部