JAVA笔记之服务端异步处理小记

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 请求层面释放容器线程,等待结果就绪后再写回响应。

方式说明

Callable<T>

Spring MVC 返回 Callable,容器线程立即释放

DeferredResult<T>

外部事件触发时完成响应

WebAsyncTask<T>

带超时控制的异步任务

AsyncContext

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 密集计算

固定大小平台线程池,不用虚拟线程


实践建议

  1. 优先简单方案:多数 Spring Boot 项目用虚拟线程 + CompletableFuture 即可,不必强行上 WebFlux。
  2. 区分 I/O 与 CPU:虚拟线程解决 I/O 阻塞;CPU 密集仍用有限线程池。
  3. 异步要有观测性:链路追踪(Micrometer Tracing)、超时、重试、死信队列。
  4. 事务边界清晰:@Async 和 MQ 消费通常在新事务中,需考虑幂等与最终一致性。
  5. Java 21+ 新项目:默认启用虚拟线程,比全面迁移 WebFlux 成本低得多。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

adix

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值