Java 服务端异步处理的核心目标是:在 I/O 等待(数据库、HTTP、消息队列)时不占用工作线程,从而提升吞吐量和资源利用率。
1. 线程池 + CompletableFuture(最常用)
基于ExecutorService 和 CompletableFuture 做任务编排,适合业务逻辑较复杂、需要组合多个异步结果的场景。
@Service
public class OrderService {
private final ExecutorService executor =Executors.newVirtualThreadPerTaskExecutor();
public CompletableFuture<OrderResult> processOrder(String orderId) {
return CompletableFuture
.supplyAsync(() -> fetchOrder(orderId), executor)
.thenCompose(order -> validatePayment(order))
.thenCompose(order -> sendNotification(order))
.exceptionally(ex -> OrderResult.failed(ex.getMessage()));
}
}
优点:API 成熟、易理解、与现有同步代码兼容好
缺点:大量并发时线程管理仍需注意(虚拟线程可缓解)
2. 虚拟线程(Java 21+,推荐)
虚拟线程是轻量级线程,适合 高并发 I/O 密集型 场景。写法接近同步代码,但底层不阻塞平台线程。
// Spring Boot 3.2+
@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {
return handler -> handler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
}
// 或直接使用
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
// 阻塞 I/O 也没问题,不会耗尽线程池
var result = httpClient.send(request, BodyHandlers.ofString());
});
}
适用:传统 Spring MVC + 大量外部调用
注意:CPU 密集型任务仍应用平台线程 + 固定线程池
3. Spring @Async
方法级异步,适合 fire-and-forget 或简单后台任务。
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public Executor taskExecutor() {
return Executors.newVirtualThreadPerTaskExecutor();
}
}
@Service
public class EmailService {
@Async
public void sendEmail(String to, String content) {
// 异步执行
}
}
注意:
- 同类内部调用
@Async不生效(需通过 Spring 代理调用) - 异常处理需配合
AsyncUncaughtExceptionHandler - 不适合需要精确背压控制的流式场景
4. Servlet 异步 / Spring MVC 异步
在 HTTP 请求层面释放容器线程,等待结果就绪后再写回响应。
| 方式 | 说明 |
|---|---|
|
|
Spring MVC 返回 Callable,容器线程立即释放 |
|
|
外部事件触发时完成响应 |
|
|
带超时控制的异步任务 |
|
|
Servlet 原生异步 API |
@GetMapping("/report")
public Callable<Report> getReport() {
return () -> reportService.generate(); // 耗时操作在另一线程执行
}
@GetMapping("/notify")
public DeferredResult<String> waitForNotify() {
DeferredResult<String> result = new DeferredResult<>(30_000L);
eventBus.subscribe(event -> result.setResult(event.getData()));
return result;
}
5. 响应式编程(Reactor / RxJava)
基于 非阻塞 I/O + 背压,适合高并发、流式数据处理。
#Spring WebFlux + Project Reactor:
@RestController
public class UserController {
@GetMapping("/users")
public Flux<User> listUsers() {
return userRepository.findAll()
.filter(User::isActive)
.take(100);
}
@GetMapping("/users/{id}")
public Mono<User> getUser(@PathVariable String id) {
return userRepository.findById(id);
}
}
技术栈:
- Project Reactor:
Mono(01)、Flux(0N) - RxJava:类似理念,生态更偏 Android/独立使用
- 底层:Netty、R2DBC(响应式数据库驱动)
优点:资源利用率高、天然背压
缺点:编程模型陡峭,调试和事务管理更复杂
6. 消息队列异步(解耦 + 削峰)
将任务投递到 MQ,由消费者异步处理,适合 可延迟、可重试、需解耦 的业务。
HTTP 请求 → 写入 Kafka/RabbitMQ → 立即返回 202 Accepted
↓
Consumer 异步处理
常见组合:
- Kafka:高吞吐、事件溯源、日志型场景
- RabbitMQ:复杂路由、延迟队列
- RocketMQ:国内业务、事务消息
Spring 示例:
@PostMapping("/orders")
public ResponseEntity<Void> createOrder(@RequestBody Order order) {
kafkaTemplate.send("order-topic", order);
return ResponseEntity.accepted().build(); // 202
}
@KafkaListener(topics = "order-topic")
public void handleOrder(Order order) {
orderService.process(order);
}
7. 事件驱动(ApplicationEvent / 领域事件)
进程内轻量异步,适合同一应用内的解耦。
// Spring 事件
@EventListener
@Async
public void onOrderCreated(OrderCreatedEvent event) {
inventoryService.reserve(event.getOrderId());
}
// 或 Guava EventBus、Axon Framework(CQRS/事件溯源)
8.选型和建议
| 场景 | 推荐方案 |
|---|---|
|
传统 CRUD + 外部 HTTP/DB 调用 |
虚拟线程 或 CompletableFuture |
|
高并发 I/O、流式 API |
WebFlux + Reactor |
|
耗时任务、削峰、跨服务解耦 |
消息队列 |
|
简单后台任务(发邮件、写日志) |
@Async |
|
长轮询、SSE、WebSocket 等待 |
DeferredResult / SseEmitter |
|
CPU 密集计算 |
固定大小平台线程池,不用虚拟线程 |
实践建议
- 优先简单方案:多数 Spring Boot 项目用虚拟线程 + CompletableFuture 即可,不必强行上 WebFlux。
- 区分 I/O 与 CPU:虚拟线程解决 I/O 阻塞;CPU 密集仍用有限线程池。
- 异步要有观测性:链路追踪(Micrometer Tracing)、超时、重试、死信队列。
- 事务边界清晰:
@Async和 MQ 消费通常在新事务中,需考虑幂等与最终一致性。 - Java 21+ 新项目:默认启用虚拟线程,比全面迁移 WebFlux 成本低得多。

273

被折叠的 条评论
为什么被折叠?



