从零开始学习JavaWeb-17


 ​​一、异步处理的必要性​

1. ​​同步阻塞的痛点​
  • ​线程资源浪费​​:同步请求中,Tomcat 线程需等待业务逻辑执行完毕(如数据库查询、远程调用),导致线程阻塞,并发能力受限。

  • ​响应延迟​​:耗时操作(如报表生成、消息推送)拖慢主线程,用户等待时间过长。

  • ​资源耗尽风险​​:高并发场景下,大量线程阻塞可能导致线程池耗尽,服务不可用。

2. ​​异步处理的优势​

​指标​

同步处理

异步处理

​线程占用​

全程占用(阻塞)

仅触发时占用(非阻塞)

​吞吐量​

低(受限于线程数)

高(线程复用)

​响应速度​

慢(等待所有操作完成)

快(立即返回中间结果)

​适用场景​

强一致性业务(支付)

非核心任务(日志、通知)


 ​​二、异步处理五大实现方案​

1. ​​线程池(@Async)​

​适用场景​​:短耗时任务(<1秒),如日志记录、本地计算。

​配置示例​​:

@Configuration  
@EnableAsync  
public class AsyncConfig {  
    @Bean  
    public Executor taskExecutor() {  
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();  
        executor.setCorePoolSize(10); // CPU密集型:N+1,IO密集型:2N  
        executor.setMaxPoolSize(100);  
        executor.setQueueCapacity(1000);  
        executor.setThreadNamePrefix("Async-Executor-");  
        return executor;  
    }  
}  

@Service  
public class NotificationService {  
    @Async // 使用线程池异步执行  
    public void sendSms(String phone) {  
        smsClient.send(phone, "您的订单已发货");  
    }  
}

​优势​​:简单易用,减少主线程等待时间。


2. ​​DeferredResult(长轮询)​

​适用场景​​:需主动推送结果的业务(如订单状态查询)。

​工作原理​​:

sequenceDiagram  
    用户->>服务端: 发起请求  
    服务端->>内存队列: 存储DeferredResult  
    服务端->>用户: 立即返回(不阻塞)  
    异步线程-->>服务端: setResult(订单状态)  
    服务端->>用户: 推送结果

​代码实现​​:

@RestController  
public class OrderController {  
    private Map<String, DeferredResult<OrderStatus>> resultMap = new ConcurrentHashMap<>();  

    @GetMapping("/order/status/{orderId}")  
    public DeferredResult<OrderStatus> getStatus(@PathVariable String orderId) {  
        DeferredResult<OrderStatus> result = new DeferredResult<>(30_000L); // 30秒超时  
        resultMap.put(orderId, result);  
        result.onCompletion(() -> resultMap.remove(orderId));  
        return result;  
    }  

    // 异步更新订单状态  
    public void updateOrderStatus(String orderId, OrderStatus status) {  
        DeferredResult<OrderStatus> result = resultMap.get(orderId);  
        if (result != null) result.setResult(status);  
    }  
}

​优势​​:支持长连接,减少客户端轮询。


3. ​​消息队列(RabbitMQ)​

​适用场景​​:跨服务解耦、流量削峰(如订单创建后的积分发放)。

​可靠性设计​​:

  • ​生产者确认​​:确保消息成功投递到队列。

  • ​消费者ACK​​:手动确认消息处理完毕,失败则重试或进入死信队列。

    ​代码示例​​:

@Bean  
public Queue orderQueue() {  
    return new Queue("order.queue", true); // 持久化队列  
}  

@Component  
public class OrderMessageSender {  
    @Autowired  
    private RabbitTemplate rabbitTemplate;  

    public void sendCreateOrder(Order order) {  
        rabbitTemplate.convertAndSend("order.exchange", "order.create", order);  
    }  
}  

@Component  
@RabbitListener(queues = "order.queue")  
public class OrderMessageHandler {  
    public void handleCreateOrder(Order order) {  
        pointService.addPoints(order.getUserId(), order.getAmount()); // 异步发放积分  
    }  
}

4. ​​事件驱动(Spring Events)​

​适用场景​​:应用内部模块解耦(如订单创建后触发日志记录和库存更新)。

​实现流程​​:

// 1. 定义领域事件  
public class OrderCreatedEvent extends ApplicationEvent {  
    private Order order;  
    public OrderCreatedEvent(Object source, Order order) {  
        super(source);  
        this.order = order;  
    }  
}  

// 2. 发布事件  
@Service  
public class OrderService {  
    @Autowired  
    private ApplicationEventPublisher eventPublisher;  

    @Transactional  
    public void createOrder(Order order) {  
        orderRepository.save(order);  
        eventPublisher.publishEvent(new OrderCreatedEvent(this, order));  
    }  
}  

// 3. 监听事件(异步执行)  
@Component  
public class OrderEventHandler {  
    @EventListener  
    @Async  
    public void handleOrderCreated(OrderCreatedEvent event) {  
        logService.record("订单创建", event.getOrder());  
        inventoryService.updateStock(event.getOrder().getItems());  
    }  
}

5. ​​响应式编程(WebFlux)​

​适用场景​​:高并发IO密集型服务(如API网关、实时数据流)。

​核心组件​​:

  • Mono:单数据流(如根据ID查询用户)。

  • Flux:多数据流(如分页查询用户列表)。

    ​代码示例​​:

@RestController  
@RequestMapping("/products")  
public class ProductController {  
    @Autowired  
    private ProductReactiveRepository repository;  

    @GetMapping("/{id}")  
    public Mono<Product> getProduct(@PathVariable String id) {  
        return repository.findById(id)  
                         .timeout(Duration.ofMillis(500)) // 超时控制  
                         .onErrorResume(e -> Mono.just(getFallbackProduct()));  
    }  

    @GetMapping  
    public Flux<Product> listProducts() {  
        return repository.findAll().delayElements(Duration.ofMillis(10));  
    }  
}

​性能优势​​:非阻塞IO模型,单线程支持万级并发。


 ​​三、异步处理的避坑指南​

1. ​​禁止异步化的场景​

​场景​

​原因​

​正确实践​

​支付核心逻辑​

需即时返回结果,保证原子性

同步处理 + 数据库事务

​库存扣减​

避免超卖(强一致性)

同步锁库存 + 事务控制

​用户登录​

需即时返回Token

同步验证 + 生成Token

2. ​​常见问题与解决方案​
  • ​事务边界问题​​:

    @Transactional  
    public void updateProfile(User user) {  
        userDao.update(user); // 同步更新  
        // 事务提交后异步记录日志  
        TransactionSynchronizationManager.registerSynchronization(  
            new TransactionSynchronization() {  
                @Override  
                public void afterCommit() {  
                    asyncService.logUpdate(user);  
                }  
            }  
        );  
    }
  • ​超时控制​​:

    • DeferredResult设置超时时间(如30秒)。

    • RabbitMQ 配置死信队列处理积压消息。


 ​​四、企业级实战:订单系统异步化改造​

1. ​​同步流程痛点​
@PostMapping("/order")  
public Result createOrderSync(OrderDTO dto) {  
    validate(dto);          // 校验(10ms)  
    lockStock(dto);         // 锁库存(50ms)  
    saveOrder(dto);         // 存订单(100ms)  
    sendSms(dto);           // 发短信(300ms)  
    return Result.success(); // 总耗时460ms  
}

​问题​​:短信发送阻塞主线程,并发量低。

2. ​​异步优化方案​
@PostMapping("/order")  
public Result createOrderAsync(OrderDTO dto) {  
    validate(dto);          // 同步核心步骤  
    lockStock(dto);  
    saveOrder(dto);  
    // 非核心操作异步化  
    asyncService.asyncSendSms(dto); // 异步发短信  
    return Result.success("订单处理中"); // 总耗时160ms  
}

​效果​​:

  • 响应时间:460ms → 160ms

  • 吞吐量:100 TPS → 1500 TPS

  • Tomcat 线程利用率:90% → 30%


 ​​五、异步方案选型对比​

​方案​

​适用场景​

​吞吐量​

​可靠性​

​复杂度​

线程池(@Async)

短耗时任务(日志)

中(无重试)

DeferredResult

长轮询(订单状态)

消息队列(RabbitMQ)

跨服务解耦(积分发放)

极高

高(持久化)

事件驱动(Spring Events)

模块解耦(日志+库存)

WebFlux

IO密集型(API网关)

极高


 ​​总结​

  1. ​核心思想​​:异步的本质是 ​​“将阻塞操作与主线程解耦”​​,通过释放线程资源提升并发能力。

  2. ​选型铁律​​:

    • 强一致性 → 同步(支付、库存)

    • 弱一致性 → 异步(日志、通知)

  3. ​避坑关键​​:

    • 事务边界用 TransactionSynchronizationManager控制。

    • 消息队列必须配置死信队列和重试机制。

  4. ​性能压测​​:

    • 线程池参数动态调整(corePoolSize = 2 * CPU核心数)。

    • 响应式编程适用于 >5000 TPS 的高并发场景。

​“异步不是银弹,而是架构师手中的手术刀——精准切割阻塞点,方能释放系统潜力。”​

​动手实践​​:

  1. @Async改造日志记录功能,对比同步/异步的吞吐量差异。

  2. 基于 RabbitMQ 实现订单创建与积分发放的解耦。

  3. 使用 WebFlux 重写商品查询接口,模拟 10K 并发压测。


​扩展学习​​:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值