@async 默认不生效,因需显式启用@enableasync且必须通过spring代理调用;常见失效原因包括未启用异步支持、本类内直接调用、方法非public、使用this调用等。

@Async 能让方法在独立线程中执行,但默认不生效——必须显式启用异步支持,且调用必须走 Spring 代理。
为什么加了 @Async 却还是同步执行?
常见现象:@Async 方法看起来被调用了,但主线程仍等待它完成,日志显示同一线程 ID;或根本没进方法体。
- 没在配置类上加
@EnableAsync,Spring 完全忽略该注解 - 方法被本类内其他方法直接调用(非 Spring 代理调用),绕过 AOP 代理层
- 目标方法不是 public 的——
@Async只对 public 方法生效 - 使用了
this.methodName()这种硬编码调用,而非注入 Bean 后调用
如何正确启用并使用 @Async?
核心是两步:开启支持 + 确保代理可达。缺一不可。
- 在任意
@Configuration类上添加@EnableAsync - 确保调用方持有 Spring 管理的 Bean 引用(比如通过
@Autowired注入),而不是new XxxService()或this.xxxMethod() - 若需自定义线程池,定义一个
TaskExecutorBean 并命名为taskExecutor,或用@Async("myExecutor")指定名称
示例配置:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean("myExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("async-");
executor.initialize();
return executor;
}
}
@Async 方法返回值和异常处理要注意什么?
返回类型受限,且异常不会自动抛给调用方——这是最容易踩坑的地方。
- 只支持
void或Future<t></t>(包括CompletableFuture<t></t>);返回其他类型会直接报错:java.lang.IllegalStateException: No result value for async method -
void方法中抛出的异常会被吞掉,除非你配置了AsyncUncaughtExceptionHandler -
Future.get()才会真正暴露异常,不调用get()就无法感知执行失败 - 推荐统一用
CompletableFuture,便于链式处理和错误回调:return CompletableFuture.supplyAsync(() -> doWork(), executor)
异步调用不等于“无序”或“可丢弃”
很多人以为加了 @Async 就能随便扔任务,结果出现数据不一致、重复提交、资源竞争等问题。
- 异步方法里如果操作数据库或共享变量,仍需考虑事务隔离与并发安全——
@Async不提供事务传播,默认没有事务上下文 - 若需事务,得额外加
@Transactional,但注意:事务不会跨线程传递,必须在异步方法内部开启新事务 - 不要在
@Async方法里依赖RequestContextHolder或SecurityContext,它们默认不继承到子线程 - 必要时手动传递上下文,例如用
SecurityContextHolder.getContext().getAuthentication()取出凭证再传入
真正难的从来不是加个注解,而是搞清线程边界、上下文生命周期和错误传播路径。










