一、异步处理概述
在传统的同步处理模式下,请求从进入系统到返回响应,整个过程都是阻塞的,直到所有操作完成才会返回结果。而异步处理允许主线程在发起某个操作后立即返回,不必等待该操作完成,被调用的方法会在后台线程中执行。
异步处理的优势:
- 提高吞吐量:服务器可以更快地释放线程处理更多请求
- 提升用户体验:快速响应用户请求,后台处理耗时操作
- 资源优化:合理利用系统资源,避免线程阻塞
二、SpringBoot 异步实现方式
1. 基于 @Async 注解
这是 Spring 提供的最简单的异步实现方式。
基本使用步骤:
- 启用异步支持
@SpringBootApplication
@EnableAsync // 开启异步支持
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- 标记异步方法
@Service
public class AsyncService {
@Async // 表示该方法将异步执行
public void asyncMethod() {
// 模拟耗时操作
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步方法执行完成");
}
}
- 调用异步方法
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/async")
public String asyncCall() {
asyncService.asyncMethod();
return "请求已接收,异步处理中...";
}
}
2. 配置自定义线程池
默认情况下,Spring 使用 SimpleAsyncTaskExecutor,但生产环境建议配置自定义线程池。
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 核心线程数
executor.setMaxPoolSize(10); // 最大线程数
executor.setQueueCapacity(100); // 队列容量
executor.setThreadNamePrefix("AsyncThread-");
executor.initialize();
return executor;
}
}
使用指定线程池:
@Async("taskExecutor")
public void asyncMethodWithConfiguredExecutor() {
// 方法实现
}
3. 异步返回值处理
异步方法可以返回 Future 或 CompletableFuture 以便获取执行结果。
@Async
public Future<String> asyncMethodWithReturn() {
// 模拟耗时操作
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new AsyncResult<>("异步方法执行完成");
}
// 调用示例
Future<String> future = asyncService.asyncMethodWithReturn();
String result = future.get(); // 阻塞获取结果
4. 异常处理
异步方法的异常不会传播到调用方,需要特殊处理:
@Async
public CompletableFuture<String> asyncMethodWithException() {
try {
// 业务逻辑
return CompletableFuture.completedFuture("Success");
} catch (Exception e) {
return CompletableFuture.failedFuture(e);
}
}
// 或者配置全局异常处理器
@Bean
public AsyncUncaughtExceptionHandler asyncUncaughtExceptionHandler() {
return (ex, method, params) -> {
System.err.println("异步方法异常: " + method.getName());
ex.printStackTrace();
};
}
三、Spring WebFlux 响应式异步
Spring WebFlux 提供了另一种异步非阻塞的编程模型。
基本使用:
@RestController
public class ReactiveController {
@GetMapping("/reactive")
public Mono<String> reactiveEndpoint() {
return Mono.fromCallable(() -> {
// 模拟耗时操作
Thread.sleep(1000);
return "Reactive Response";
}).subscribeOn(Schedulers.boundedElastic());
}
}
四、异步处理最佳实践
- 合理配置线程池:根据业务需求设置合适的线程数和队列容量
- 避免长时间阻塞:异步方法中不应有长时间阻塞操作
- 异常处理:确保异步异常能被正确处理和记录
- 资源清理:异步操作中打开的资源需要手动清理
- 监控:对异步任务执行情况进行监控
- 避免过度使用:不是所有场景都适合异步,简单操作同步可能更高效
五、常见问题与解决方案
- @Async 不生效:
- 确保 @EnableAsync 已添加
- 异步方法必须定义在另一个类中(Spring 代理限制)
- 不能是 private 方法
- 线程池耗尽:
- 调整线程池配置
- 使用不同的线程池隔离不同业务
- 上下文丢失:
- 安全上下文、事务上下文等可能无法传递
- 解决方案:使用 DelegatingSecurityContextAsyncTaskExecutor 等装饰器
- 任务结果跟踪:
- 使用 Future 或 CompletableFuture 跟踪任务状态
- 考虑使用更复杂的任务管理系统如 Spring Batch
六、性能考量
- 线程池大小:通常设置为 CPU 核心数的 2-3 倍
- 队列大小:根据业务特点设置,避免内存溢出
- 任务拆分:将大任务拆分为小任务并行执行
- 超时设置:对异步任务设置合理的超时时间