当前位置: 首页 > news >正文

每日一博 - 异步编程最佳实践

文章目录

  • 前言
  • 一、异步的 实现方案
    • 1. 线程与线程池
    • 2. Future
    • 3. CompletableFuture
    • 4. Spring `@Async`
    • 5. Spring 事件驱动
    • 6. 消息队列
    • 7. 响应式编程(Reactor)
    • 8. 异步 HTTP 与非阻塞 IO
  • 二、常见问题
  • 三、性能压测对比
  • 四、最佳实践
  • 总结

在这里插入图片描述

前言

在高并发场景下,同步调用往往因 I/O 阻塞造成线程资源浪费,严重时会导致系统雪崩。例如xx接口响应从 50ms 升至 2s,导致 200 个线程被阻塞,仅 10s 即触及线程池上限,引发链式故障。

为了解决这一痛点,异步编程应运而生,其三大核心价值:

  1. 资源释放:I/O 等待期间释放线程,提高吞吐量。
  2. 故障隔离:单个服务异常不影响整体流程。
  3. 流量削峰:利用消息队列缓存突发流量,平滑请求。

一、异步的 实现方案

1. 线程与线程池

核心原理:物理线程并行执行任务。

// Java 21+ 虚拟线程示例
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
executor.submit(() -> {System.out.println("异步任务执行: " + Thread.currentThread().getName());
});
  • 适用场景:简单、重量级任务。
  • 优劣:实现简单,但线程上下文切换成本较高,不适合超高并发。

2. Future

特点:提交后返回 Future,需要 get() 阻塞等待结果。

ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future = executor.submit(() -> {Thread.sleep(2000);return "结果数据";
});
String result = future.get(); // 阻塞
  • 缺陷:阻塞等待、难链式编排、超时和异常处理需手动实现。

3. CompletableFuture

首选方案:非阻塞任务编排。

CompletableFuture.supplyAsync(() -> fetchOrder(123)).thenApplyAsync(order -> calculatePrice(order)).thenAccept(price -> sendNotification(price)).exceptionally(ex -> {log.error("处理失败", ex);return null;});
  • 超时控制(JDK9+):

    CompletableFuture.supplyAsync(this::longTask).orTimeout(2, TimeUnit.SECONDS).whenComplete((res, ex) -> {if (ex instanceof TimeoutException) {// 超时处理}});
    
  • 适用场景:复杂异步编排、链式依赖。


4. Spring @Async

企业级简易方案,需自定义线程池:

@Configuration
@EnableAsync
public class AsyncConfig {@Bean("taskExecutor")public Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(10);executor.setMaxPoolSize(50);executor.setQueueCapacity(100);executor.setThreadNamePrefix("Async-");return executor;}
}@Service
public class OrderService {@Async("taskExecutor")public CompletableFuture<Order> createOrder(OrderDTO dto) {// 异步逻辑return CompletableFuture.completedFuture(order);}
}
  • 避坑:避免自调用、动态调整参数、监控队列堆积。

5. Spring 事件驱动

解耦利器,常用于业务辅助操作:

public class OrderCreatedEvent extends ApplicationEvent {private final Order order;// 构造省略
}applicationContext.publishEvent(new OrderCreatedEvent(this, order));@Component
public class BonusServiceListener {@Async@EventListenerpublic void handleOrderEvent(OrderCreatedEvent event) {addBonus(event.getOrder().getUserId());}
}
  • 优势:发布–订阅模型,业务模块解耦。

6. 消息队列

分布式解耦,缓冲和削峰:

// RocketMQ 生产者
Message msg = new Message("OrderTopic", "CREATE", orderJson.getBytes());
producer.send(msg);// RocketMQ 消费者
consumer.subscribe("OrderTopic", "*", (msgs, context) -> {for (MessageExt msg : msgs) {processOrder(new String(msg.getBody()));}return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
  • 可靠性:事务消息、死信队列、幂等消费。

7. 响应式编程(Reactor)

高并发流处理,内置背压:

Flux.range(1, 100).parallel().runOn(Schedulers.parallel()).map(this::intensiveCalculation).subscribe(this::updateDB);
  • 适用场景:实时数据流,如行情推送。

8. 异步 HTTP 与非阻塞 IO

事件驱动模型

vertx.createHttpServer().requestHandler(req -> {dbClient.query("SELECT * FROM users", res -> {req.response().putHeader("content-type", "application/json").end(encodeJson(res.result()));});}).listen(8080);
  • 对比 BIO vs NIO

    指标阻塞IO非阻塞IO
    线程数1000请求=1000线程1000请求=4线程
    CPU 利用率低(频繁切换)高(事件驱动)
    吞吐量< 5,000 QPS> 30,000 QPS

二、常见问题

  1. 回调地狱

    • 传统回调嵌套:

      serviceA.call(resultA -> {serviceB.call(resultA, resultB -> {serviceC.call(resultB, resultC -> { /* ... */ });});
      });
      
    • CompletableFuture 优雅链式:

      CompletableFuture.supplyAsync(serviceA::call).thenCompose(serviceB::call).thenCompose(serviceC::call).thenAccept(this::finalAction);
      
  2. 上下文丢失

    • 使用 TransmittableThreadLocal 保持 ThreadLocal:

      TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
      context.set("user123");
      CompletableFuture.runAsync(() -> {System.out.println(context.get()); // user123
      }, TtlExecutors.getTtlExecutorService(executor));
      
  3. 分布式事务一致性

    • Saga 模式:将大事务拆分为可补偿的小事务,结合消息队列或状态机实现最终一致性。

三、性能压测对比

方案延迟(ms)吞吐量(QPS)线程数适用场景
线程池452,000200+简单任务
Future402,500200+需阻塞获取结果
CompletableFuture258,00050复杂编排
Spring @Async307,00050Spring 生态
消息队列6012,00020分布式解耦
响应式编程1515,0004实时流处理
非阻塞IO1030,0004网络密集型服务

测试环境:AWS c5.4xlarge(16 核 32GB)


四、最佳实践

  1. 选型策略

    • 初创期:@Async + 线程池
    • 发展期:CompletableFuture 任务编排
    • 高并发期:响应式编程 + 非阻塞IO
    • 分布式期:消息队列 + 事务最终一致性
  2. 避坑指南

    • 死锁预防:避免异步任务间循环依赖。
    • 超时控制:所有异步操作必须设置超时。
    • 幂等设计:消息重试时防止重复消费。
    • 上下文传递:使用 TransmittableThreadLocal 传递上下文。
  3. 监控体系

    • 线程池:活跃线程数、队列深度、拒绝次数
    • 消息队列:积压量、消费延迟
    • 链路追踪:异步调用链可视化

总结

选择最适合场景的方案,才能在性能、可靠性与可维护性之间找到最佳平衡。

在这里插入图片描述

http://www.dtcms.com/a/312436.html

相关文章:

  • ABAP SQL更新DB小技巧 WITH INDICATORS
  • Python-初学openCV——图像预处理(六)
  • 【GitHub探索】Prompt开发评测平台CozeLoop踩坑体验
  • 【gStreamer】Windows VS2022 C++ 项目中调用gstreamer相关函数,获取无线摄像头视频
  • LLM - 智能体工作流设计模式
  • C++ 设计模式综合实例
  • 设计原则和设计模式
  • 浅窥Claude-Prompting for Agents的Talk
  • Go语法:闭包
  • AD方案(OpenLDAP或微软AD)适配信创存在的不足以及可能优化方案
  • 风光储综合能源系统双层优化规划设计【MATLAB模型实现】
  • Android 之 WebView与HTML交互
  • ticdc同步集群部署
  • Java ++i 与 i++ 底层原理
  • 六、Linux核心服务与包管理
  • Unity_数据持久化_IXmlSerializable接口
  • java:判断两个实例(对象)相等
  • 多向量检索:lanchain,dashvector,milvus,vestorsearch,MUVERA
  • RabbitMQ面试精讲 Day 9:优先级队列与惰性队列
  • SQL154 插入记录(一)
  • 十八、Javaweb-day18-前端实战-登录
  • JavaScript 性能优化实战指南:从运行时到用户体验的全面提升​
  • 【openlayers框架学习】十:openlayers中控件的使用
  • 学习笔记《区块链技术与应用》第六天 问答 匿名技术 零知识证明
  • Apple基础(Xcode④-Flutter-Platform Channels)
  • Stream 过滤后修改元素,却意外修改原列表
  • Swift 运算符
  • 【Django】-9- 单元测试和集成测试(上)
  • Android 之 蓝牙通信(4.0 BLE)
  • Redis+Lua的分布式限流器