在高并发场景下,同步处理(一个请求一个线程等待完成)容易导致线程池耗尽 —— 比如用户下单后需要发送短信、推送消息、更新统计数据,若同步执行这些非核心操作,会显著增加接口响应时间。异步处理通过将非核心流程剥离到后台执行,让主线程快速返回,大幅提升系统吞吐量。
异步处理的核心价值
异步处理的核心是 “非核心流程后置化”,带来的好处:
- 缩短接口响应时间:用户无需等待非核心操作完成
- 提高系统吞吐量:主线程快速释放,可处理更多请求
- 削峰填谷:通过消息队列缓冲突发流量,避免下游服务被压垮
主流异步实现方案
1. 线程池异步:简单场景的首选
通过 Java 的ThreadPoolExecutor或 Spring 的@Async注解,将任务提交到线程池执行。
代码示例(Spring @Async) :
// 1. 配置线程池
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); // 核心线程数
executor.setMaxPoolSize(20); // 最大线程数
executor.setQueueCapacity(100); // 队列容量
executor.setThreadNamePrefix("async-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略:让提交任务的线程执行,避免任务丢失
return executor;
}
}
// 2. 异步服务
@Service
public class AsyncService {
@Async("taskExecutor")
public CompletableFuture<Void> sendSms(String phone, String content) {
// 发送短信逻辑(模拟耗时操作)
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
log.info("短信发送成功:{}", phone);
return CompletableFuture.completedFuture(null);
}
}
// 3. 业务中调用
@Service
public class OrderService {
@Autowired
private AsyncService asyncService;
public Order createOrder(OrderDTO orderDTO) {
// 1. 核心流程:创建订单(同步执行)
Order order = orderMapper.insert(orderDTO);
// 2. 非核心流程:发送短信通知(异步执行)
asyncService.sendSms(orderDTO.getPhone(), "您的订单已创建,订单号:" + order.getOrderNo());
// 3. 其他异步操作:推送消息、更新统计等
return order;
}
}
适用场景:非核心、轻量级操作(如日志记录、简单通知),且无需关心执行结果。
2. 消息队列异步:分布式场景的可靠选择
通过 RabbitMQ、Kafka 等消息队列,将任务封装为消息发送到队列,由消费者异步处理。
优势:
-
可靠性:消息持久化,避免服务宕机导致任务丢失
-
可追溯:消息有发送、消费记录,便于问题排查
-
解耦:生产者和消费者完全解耦,可独立扩容
代码示例(RabbitMQ) :
// 1. 配置队列和交换机
@Configuration
public class RabbitConfig {
@Bean
public Queue orderNotifyQueue() {
return QueueBuilder.durable("order.notify.queue") // 持久化队列
.withArgument("x-dead-letter-exchange", "order.dlq.exchange") // 死信交换机
.build();
}
}
// 2. 生产者:发送消息
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
public Order createOrder(OrderDTO orderDTO) {
Order order = orderMapper.insert(orderDTO);
// 发送消息到队列
OrderNotifyMessage message = new OrderNotifyMessage(order.getOrderNo(), orderDTO.getPhone());
rabbitTemplate.convertAndSend("order.notify.exchange", "order.notify.key", message);
return order;
}
}
// 3. 消费者:处理消息
@Component
public class OrderNotifyConsumer {
@Autowired
private SmsService smsService;
@Autowired
private PushService pushService;
@RabbitListener(queues = "order.notify.queue")
public void handleOrderNotify(OrderNotifyMessage message) {
// 发送短信
smsService.send(message.getPhone(), "订单创建通知:" + message.getOrderNo());
// 推送消息
pushService.push(message.getPhone(), "您有新订单");
}
}
适用场景:分布式系统、跨服务调用、需要保证任务一定执行的场景(如支付结果通知、订单状态同步)。
异步处理的注意事项
1. 异常处理
- 线程池异步:需捕获异常,避免线程因未处理异常而终止(可通过
CompletableFuture.exceptionally()处理) - 消息队列:配置死信队列(DLQ),处理消费失败的消息(如重试几次后移入死信队列,人工干预)
2. 数据一致性
异步操作可能导致数据最终一致性,需设计补偿机制:
- 例:订单创建成功但短信发送失败,可通过定时任务重试发送
- 关键场景(如支付异步通知)需实现 “幂等性”,避免重复处理
3. 监控与追踪
- 记录异步任务的执行状态(成功 / 失败次数、耗时)
- 用 TraceID 串联同步流程和异步流程,便于全链路追踪
避坑指南
- 不是所有场景都适合异步:核心流程(如订单创建、支付扣减)必须同步执行,确保即时反馈
- 避免过度异步:简单操作(如记录日志)用线程池即可,无需引入消息队列增加复杂度
- 控制异步任务量:线程池队列和消息队列容量有限,需监控队列长度,避免任务堆积导致 OOM 或消息丢失