目录
Spring 框架中用于实现异步方法调用的注解是 @Async
。这个注解允许方法在独立的线程中异步执行,从而避免阻塞主线程,提升系统吞吐量和响应速度。
1. 核心注解:@Async
- 作用:标记一个方法为异步执行,Spring 会通过线程池启动新线程执行该方法。
- 使用条件:
-
- 在 Spring Boot 启动类或配置类上添加
@EnableAsync
启用异步支持。 - 异步方法必须定义在 Spring管理的Bean中(如
@Service
、@Component
注解的类)。 - 调用异步方法时,需通过 Spring代理对象调用(直接调用同类中的异步方法会失效)。(这一点和事务失效的一种情况有点相似)
- 在 Spring Boot 启动类或配置类上添加
2. 基础使用示例
(1)启用异步支持
@SpringBootApplication
@EnableAsync //启用异步支持
public class Application {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
(2)定义异步方法
@Service
public class MyService {
@Async // 标记为异步方法
public void asyncTask() {
// 模拟耗时操作
System.out.println("异步任务执行线程: " + Thread.currentThread().getName());
}
public void syncTask() {
System.out.println("同步任务执行线程: " + Thread.currentThread().getName());
}
}
(3)调用异步方法
@RestController
public class MyController {
@Autowired
private MyService myService;
@GetMapping("/test-async")
public String testAsync() {
myService.asyncTask(); //异步执行
myService.syncTask(); //同步执行
return "Check console logs!";
}
}
输出结果:
异步任务执行线程: task-1
同步任务执行线程: http-nio-8080-exec-1
3. 高级配置
(1)自定义线程池
默认情况下,Spring 使用 SimpleAsyncTaskExecutor
(非池化线程),建议自定义线程池:
@Configuration
public class AsyncConfig {
@Bean(name = "myTaskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("MyAsyncThread-");
executor.initialize();
return executor;
}
}
(2)指定线程池执行器
@Async("myTaskExecutor") // 指定使用自定义线程池
public void asyncTaskWithCustomPool() {
//业务逻辑
}
4. 返回值处理
(1)无返回值
直接使用 void
:
@Async
public void asyncVoidMethod() { /* ... */ }
(2)有返回值
返回 Future
或 CompletableFuture
:
@Async
public Future<String> asyncFutureMethod() {
return new AsyncResult<>("Task result");
}
@Async
public CompletableFuture<String> asyncCompletableFutureMethod() {
return CompletableFuture.completedFuture("Task result");
}
调用示例:
Future<String> future = myService.asyncFutureMethod();
String result = future.get(); // 阻塞等待结果
5. 常见问题与解决
(1)异步方法不生效
- 原因:未启用
@EnableAsync
,或方法未通过代理对象调用。 - 解决:
-
- 确保启动类添加
@EnableAsync
。 - 避免同类内部调用异步方法(如
this.asyncTask()
)。
- 确保启动类添加
(2)线程池配置无效
- 原因:未正确注入自定义线程池。
- 解决:检查
@Async("beanName")
中的 Bean 名称是否匹配。
(3)异常处理
异步方法默认不传播异常到调用方,需通过 AsyncUncaughtExceptionHandler
处理:
@Configuration
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
//返回自定义线程池
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> {
System.err.println("异步方法异常: " + method.getName());
ex.printStackTrace();
};
}
}
6. 适用场景
- 耗时操作:发送邮件、生成报表、调用外部 API。
- 非关键路径任务:日志记录、数据缓存更新。
- 高并发优化:减少请求响应时间,提升吞吐量。
7.总结
- 核心注解:
@Async
+@EnableAsync
。 - 关键配置:自定义线程池、异常处理。
- 注意事项:避免同类调用、合理控制线程池参数。
通过合理使用 @Async
,可以显著提升 Spring 应用的并发处理能力。