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
  • 生产:自定义线程池 + 异常处理
  • 场景:耗时、非核心、可并行任务

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

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

相关推荐
ulias2122 小时前
leetcode热题 - 4
算法·leetcode·职场和发展
AC赳赳老秦2 小时前
DBA 专属方案:用 OpenClaw 实现 SQL 语句优化、慢查询分析、数据库备份巡检全自动化
服务器·前端·数据库·ffmpeg·自动化·deepseek·openclaw
夏末蝉未鸣012 小时前
跨境电商SQL Server报表生成优化:索引一改,600秒变75秒
数据库
MicroTech20252 小时前
微算法科技(NASDAQ :MLGO)量子化边缘检测技术:重塑图像处理的新范式
图像处理·科技·算法
WolfGang0073212 小时前
代码随想录算法训练营 Day47 | 图论 part05
算法·图论
hhb_6182 小时前
SQL高性能查询优化与复杂场景实战指南
服务器·数据库·sql
我是无敌小恐龙2 小时前
Java SE 零基础入门Day06 方法重载+Debug调试+String字符串全套API详解(超全干货)
java·开发语言·人工智能·python·transformer·无人机·量子计算
xiaoye37082 小时前
java接口文档工具 swagger2和swagger3对比
java·服务器·前端
2301_773553622 小时前
Redis怎样优化复制缓冲池大小_调大repl-backlog-size减少频繁的全量同步触发
jvm·数据库·python