5月29日 01:38

Spring Boot 中如何实现异步编程?

Spring Boot 通过 @EnableAsync + @Async 实现声明式异步编程。在配置类上标注 @EnableAsync 开启支持,在方法上标注 @Async 即可在独立线程执行;默认使用 SimpleAsyncTaskExecutor(每次新建线程),生产环境应自定义 ThreadPoolTaskExecutor 并通过 @Async("executorName") 指定线程池。有返回值的方法返回 CompletableFuture,调用方可通过 future.get()CompletableFuture.allOf() 组合多个异步结果。异常处理方面,返回 CompletableFuture 的方法异常会传播到 future,void 方法需实现 AsyncUncaughtExceptionHandler。注意同类内部调用 @Async 方法不生效(绕过代理)。

追问

  • ThreadPoolTaskExecutor 的核心参数如何设置? IO 密集型核心线程数可设为 CPU 核数 * 2,队列容量适当放大;CPU 密集型核心线程数为 CPU 核数 + 1,队列不宜过大;拒绝策略推荐 CallerRunsPolicy 由提交线程执行降速。
  • @Async 方法为什么同类调用不生效?如何解决? @Async 依赖 AOP 代理,this.method() 绕过代理直接调用原始方法;解决方案是注入自身代理 @Lazy private XxxService self 后通过 self.method() 调用。
  • CompletableFuture 的 thenCombine 和 thenCompose 有何区别? thenCombine 将两个独立异步结果合并(BiFunction),thenCompose 用于异步结果串联(flatMap 语义,前一步结果决定后一步操作)。
  • @Async 和 @Transactional 一起使用有什么陷阱? 事务上下文绑定 ThreadLocal,异步方法在新线程执行导致事务不传播;应在异步方法内部调用另一个 Bean 的事务方法,而非叠加注解。
  • 如何将 RequestContext 传播到异步线程? 使用 TaskDecorator 在任务提交时捕获主线程的 RequestAttributes,在异步线程执行前设置,执行后清除。

写段代码

java
@EnableAsync @Configuration public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor(); ex.setCorePoolSize(5); ex.setMaxPoolSize(20); ex.setQueueCapacity(100); ex.setThreadNamePrefix("async-"); ex.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); ex.initialize(); return ex; } }
标签:Spring Boot