Spring Boot 优雅实现异步调用:从入门到自定义线程池与异常处理

在 Spring Boot 项目里,同步接口经常会被慢接口拖垮响应速度。异步调用可以把耗时任务丢到独立线程,让主线程快速返回,提升接口吞吐量与用户体验。

这篇文章用最清晰、最工程化的方式,带你从零学会 Spring Boot 异步开发,包含默认使用、自定义线程池、异常处理、避坑要点。


一、先搞懂:同步 vs 异步

  • 同步:任务串行执行,必须等上一个完成才能走下一个,主线程阻塞。
  • 异步:任务提交给独立线程执行,主线程不用等,直接返回。

适用场景:

  • 发送短信、推送消息
  • 记录日志、上报埋点
  • 调用第三方慢接口
  • 批量数据处理

二、Spring Boot 异步最简实现(3步搞定)

Spring 提供 @Async + @EnableAsync 开箱即用。

1. 启动类/配置类开启异步

复制代码
@SpringBootApplication
@EnableAsync // 开启异步
public class AsyncApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsyncApplication.class, args);
    }
}

2. 编写异步 Service

规则

  • 方法必须是 public

  • 不能是本类内部调用(AOP 代理限制)

  • 返回值只能是 voidFuture<T>

    @Service
    @Slf4j
    public class AsyncServiceImpl {

    复制代码
      // 无返回值异步
      @Async
      public void asyncVoidTask() throws InterruptedException {
          Thread.sleep(3000);
          log.info("异步任务执行,线程:{}", Thread.currentThread().getName());
      }
    
      // 带返回值异步
      @Async
      public Future<String> asyncFutureTask() throws InterruptedException {
          Thread.sleep(5000);
          log.info("异步任务执行,线程:{}", Thread.currentThread().getName());
          return new AsyncResult<>("任务执行完成");
      }

    }

3. Controller 调用

复制代码
@RestController
@Slf4j
public class AsyncController {

    @Autowired
    private AsyncServiceImpl asyncService;

    @GetMapping("/async/void")
    public String testVoid() {
        long start = System.currentTimeMillis();
        log.info("主线程:{}", Thread.currentThread().getName());
        asyncService.asyncVoidTask();
        return "耗时:" + (System.currentTimeMillis() - start) + "ms";
    }

    @GetMapping("/async/future")
    public String testFuture() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        Future<String> future = asyncService.asyncFutureTask();
        // 阻塞获取结果
        String result = future.get();
        return result + ",总耗时:" + (System.currentTimeMillis() - start) + "ms";
    }
}

运行结果

  • /async/void:立即返回,耗时几毫秒,异步任务后台执行。
  • /async/future:会阻塞 5 秒,但依然是异步执行。

三、自定义异步线程池(生产必须用)

Spring 默认用 SimpleAsyncTaskExecutor,不重用线程,高并发会OOM。生产环境必须自定义线程池

复制代码
@Configuration
public class AsyncConfig implements AsyncConfigurer {

    @Override
    @Bean("asyncTaskExecutor")
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数
        executor.setCorePoolSize(5);
        // 最大线程数
        executor.setMaxPoolSize(10);
        // 队列容量
        executor.setQueueCapacity(200);
        // 线程名前缀
        executor.setThreadNamePrefix("async-task-");
        // 关机时等待任务完成
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 等待时长
        executor.setAwaitTerminationSeconds(60);
        // 拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        executor.initialize();
        return executor;
    }
}

使用时指定线程池:

复制代码
@Async("asyncTaskExecutor")
public void asyncVoidTask() { ... }

四、自定义异步异常处理器

异步方法里抛异常,主线程感知不到。我们可以统一捕获。

复制代码
@Configuration
public class AsyncConfig implements AsyncConfigurer {

    // 上面的线程池配置...

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -> {
            log.error("异步方法异常:{}", method.getName());
            log.error("异常信息:", ex);
        };
    }
}

效果:

异步任务报错后,不会直接吞掉,会按你定义的方式打印/告警。


五、@Async 工作原理(面试常问)

  1. @EnableAsync 开启 AOP 代理。
  2. @Async 方法被调用时,Spring 拦截并提交到线程池。
  3. 由线程池里的线程执行目标方法。
  4. 主线程立即返回,不阻塞。

六、避坑指南(非常重要)

  1. 异步方法必须是 public,private 不生效。
  2. 不能同类内部调用 ,比如 this.asyncMethod(),不走代理。
  3. 返回值只能是 void / Future ,用 ListenableFuture 也可以。
  4. 生产必须自定义线程池,默认会无限创建线程。
  5. 异常必须单独处理,主线程 catch 不到。
  6. 事务不生效:异步方法和主线程不在一个事务里。

七、总结

Spring Boot 异步非常简单:

  • 开启:@EnableAsync
  • 标记:@Async
  • 生产:自定义线程池 + 异常处理
  • 场景:耗时、非核心、可并行任务

用好异步,能让你的接口性能直接上一个台阶。

降重鸟技术团队文章,勿全文转发

相关推荐
奇特認1 小时前
mysql 集群技术 3.高可用之 MHA
数据库·mysql
rannn_1114 小时前
【力扣hot100】链表专题|160、206、234、141、142
java·算法·leetcode·链表·面试·开发
Bioinfo Guy4 小时前
高分Panel复现系列|转录因子网络太乱?用模块框把重点圈出来
数据库·生物信息学·生信可视化
数模竞赛Paid answer4 小时前
2026年华东杯数学建模B题医药物流安排问题解题全过程文档及程序
算法·数学建模·数据分析·华东杯
不会代码的小猴4 小时前
21. 泛型编程上
开发语言·c++·笔记·算法
ltl5 小时前
Disaggregated DB 合集:Socrates、PolarDB、Taurus 的共同模式
数据库
IKUN家族5 小时前
Spring IoC&DI
java·spring·rpc
AI备案指南-满满5 小时前
大模型与算法备案全流程详解:从零到通过的完整指南
人工智能·算法·备案·大模型备案·算法备案
江畔柳前堤5 小时前
LLM 训练核心机制深度解析:Warmup、Cosine Decay 与 Perplexity 的完整知识体系
网络·人工智能·深度学习·算法·机器学习·语音识别
一只旭宝5 小时前
细讲C加加【9】C++ std::function与std::bind详解|仿函数、绑定器、类成员绑定、占位符、成员偏移指针
开发语言·c++·算法