SpringBoot项目@Async异步注解不生效 接口始终运行于同一线程
SpringBoot @Async异步功能不生效问题修复
问题根因
异步功能完全失效的核心原因是你用@Async标注的方法加了static静态修饰符。
Spring的@Async实现基于AOP动态代理,只有通过Spring容器管理的代理对象调用非静态、非私有的公开实例方法时,才会触发切面逻辑,把方法提交到指定线程池异步执行。静态方法属于类级别方法,代理逻辑无法拦截,因此所有方法调用都会直接在当前请求线程执行,完全不会用到你配置的线程池,所以调试时会看到所有请求都运行在同一个线程中。
修复方案
- 移除异步方法的
static修饰符
确保getExecutionDatafromDb()方法是Spring管理的asyncService类中的公开实例方法,不要在Controller类中直接定义异步方法,保持现在通过注入的asyncService实例调用方法的写法即可(同类别内直接用this调用的自调用场景会导致代理失效,你现在的跨Bean调用写法是正确的)。
修正后的方法定义示例:@Async("threadPoolTaskExecutor") // 删掉static修饰符,其余业务逻辑保持原有实现即可 public CompletableFuture<Object> getExecutionDatafromDb() { long start = System.currentTimeMillis(); Object executionData = ""; db = mongoClient.getDatabase(database); collection = db.getCollection("executiondata"); // 省略原有Mongo查询、数据处理逻辑 logger.info("Fecthing data "+Thread.currentThread().getName()); // 省略原有序列化、游标关闭逻辑 long end = System.currentTimeMillis(); logger.info("Total time {}", (end - start)); return CompletableFuture.completedFuture(json); } - (建议补充)完善线程池配置
你当前的线程池配置没有指定拒绝策略,当线程数和队列都打满时会抛出未捕获的异常,建议补充拒绝策略配置:@Configuration @EnableAsync public class AsyncConfig { @Bean("threadPoolTaskExecutor") public TaskExecutor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(2); executor.setMaxPoolSize(2); executor.setQueueCapacity(100); executor.setThreadNamePrefix("AsyncThread-"); // 队列满时由提交任务的调用线程执行任务,避免任务丢失 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }
验证方式
重启服务后调用测试接口,查看日志中打印的线程名,如果出现你配置的AsyncThread-*前缀的线程名,而不是Tomcat默认的http-nio-*-exec-*请求线程名,就说明异步功能已经正常生效。
额外注意:如果后续需要在同一个Service类中调用异步方法,必须通过注入的代理实例调用,不能直接用
this调用,否则同样会出现AOP不拦截、异步失效的问题。
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

