@async异步调用需三步:启用@enableasync、配置threadpooltaskexecutor线程池、通过spring代理调用;必须public方法且非自调用,推荐返回completablefuture,避免默认simpleasynctaskexecutor导致oom。

在 Spring 中使用 @Async 实现异步方法调用,核心是让方法在独立线程中执行,不阻塞当前调用线程。但直接加注解不会生效——必须完成启用、配置线程池、确保代理生效三步,否则方法仍是同步执行。
开启异步支持
在任意配置类或启动类上添加 @EnableAsync 注解:
- Spring Boot 项目通常加在主启动类上(
@SpringBootApplication所在类) - 非 Boot 项目需配合
@Configuration使用 - 该注解会启用 Spring 的异步代理机制,是
@Async生效的前提
定义异步方法
被 @Async 标记的方法需满足以下条件:
- 必须是 public 方法(private / protected / package-private 不生效)
- 不能是同一个类内部的 self-invocation(即本类中 A 方法调 B 方法,B 加了 @Async 也不会异步)——因为代理对象未介入
- 推荐返回
CompletableFuture<t></t>或void;若返回值为普通类型(如 String),需注意调用方无法直接获取结果,应通过回调或 future.get() 获取(后者会阻塞)
示例:
```java@Service
public class TaskService {
@Async
public CompletableFuture
try {
Thread.sleep(2000); // 模拟耗时操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return CompletableFuture.completedFuture("Done: " + input);
}
}
配置自定义线程池(强烈推荐)
不配置时 Spring 会使用默认的 SimpleAsyncTaskExecutor,它为每次调用新建线程,无复用、无限制,高并发下极易 OOM。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 定义一个
TaskExecutorBean,命名为taskExecutor(Spring 会自动识别) - 使用
ThreadPoolTaskExecutor,合理设置核心线程数、最大线程数、队列容量和拒绝策略 - 可选:设置线程名称前缀,便于日志追踪
示例配置:
```java@Configuration
public class AsyncConfig {
@Bean("taskExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("async-task-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
正确调用与结果处理
异步方法需由 Spring 代理对象调用才生效:
- 在 Controller 或 Service 中注入
TaskService,再调用其方法(不要 new 实例) - 若返回
CompletableFuture,可用thenApply、thenAccept做后续处理,或组合多个异步任务 - 避免在 Web 层直接
future.get()阻塞主线程;如需等待结果,建议用 WebFlux 或异步 Servlet 支持
调用示例:
```java@RestController
public class TaskController {
@Autowired
private TaskService taskService;
@GetMapping("/run")
public String runTask() {
// 立即返回,不等异步任务结束
taskService.doAsyncTask("test").whenComplete((result, ex) -> {
if (ex == null) {
System.out.println("Async result: " + result);
} else {
ex.printStackTrace();
}
});
return "Task submitted";
}
}
不复杂但容易忽略:代理机制、线程池配置、调用方式三者缺一不可。配好之后,异步方法就真正脱离主线程,在后台安静执行了。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










