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; } }