news 2026/4/18 5:23:35

Spring Boot 中基于线程池的订单创建并行化实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot 中基于线程池的订单创建并行化实践

一、背景

1.1 业务背景

  • 以电商系统「订单创建」接口为例

  • 一个用户下单请求,往往需要完成多个业务步骤:

    • 校验库存

    • 校验用户信息

    • 计算订单价格

    • 锁库存

    • 创建订单

1.2 问题描述

  • 传统实现方式:串行执行

  • 在高并发场景下:

    • 接口 RT 高

    • 线程被长时间占用

    • 系统吞吐下降

1.3 技术挑战

  • 哪些任务可以并行?

  • 如何安全、高效地并行?

  • 如何在 Spring Boot 中正确使用线程池

  • 二、业务场景分析与并行拆分

    2.1 订单创建流程拆解

    步骤是否存在依赖是否可并行
    校验库存
    校验用户
    计算价格
    锁库存依赖库存校验
    创建订单依赖前置结果

    2.2 并行化设计思路

  • 无依赖的校验类任务 → 并行

  • 存在业务依赖的核心流程 → 串行

  • 线程池只用于短生命周期任务

三、技术选型与整体设计

3.1 为什么不直接 new Thread?

  • 线程创建成本高

  • 无法控制并发量

  • 高并发下容易导致 JVM 失控

3.2 为什么选择线程池 + CompletableFuture?

  • 线程复用,降低系统开销

  • 明确的并发上限

  • 支持任务编排(allOf / thenCombine)

3.3 在 Spring Boot 中的正确姿势

  • 线程池必须交由 Spring 管理

  • 使用ThreadPoolTaskExecutor

  • 为业务定制专用线程池,避免互相影响

四、线程池设计与配置(Core)

4.1 线程池配置代码

@Configuration public class OrderThreadPoolConfig { @Bean("orderExecutor") public ThreadPoolTaskExecutor orderExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(8); executor.setMaxPoolSize(16); executor.setQueueCapacity(200); executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix("order-create-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }

4.2 关键参数说明

  • corePoolSize:常态并发能力

  • maxPoolSize:应对突发流量

  • queueCapacity:缓冲任务,防止雪崩

  • RejectedExecutionHandler

    • 选择CallerRunsPolicy实现自然限流

4.3 线程池定位

  • Web 请求内使用

  • IO + 轻计算混合型线程池

  • 非长任务、非阻塞型任务

五、核心业务实现

5.1 校验 Service(模拟 RPC / DB)

@Service public class OrderCheckService { public boolean checkStock(Long skuId) { sleep(100); return true; } public boolean checkUser(Long userId) { sleep(80); return true; } public int calcPrice(Long skuId) { sleep(120); return 99; } private void sleep(long ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }

5.2 订单创建核心逻辑

@Service public class OrderService { @Resource(name = "orderExecutor") private Executor orderExecutor; @Autowired private OrderCheckService orderCheckService; public String createOrder(Long userId, Long skuId) throws Exception { long start = System.currentTimeMillis(); CompletableFuture<Boolean> stockFuture = CompletableFuture.supplyAsync( () -> orderCheckService.checkStock(skuId), orderExecutor); CompletableFuture<Boolean> userFuture = CompletableFuture.supplyAsync( () -> orderCheckService.checkUser(userId), orderExecutor); CompletableFuture<Integer> priceFuture = CompletableFuture.supplyAsync( () -> orderCheckService.calcPrice(skuId), orderExecutor); CompletableFuture.allOf( stockFuture, userFuture, priceFuture).join(); if (!stockFuture.get()) { throw new RuntimeException("库存不足"); } int price = priceFuture.get(); lockStock(skuId); saveOrder(userId, skuId, price); return "success, cost=" + (System.currentTimeMillis() - start) + "ms"; } private void lockStock(Long skuId) { sleep(50); } private void saveOrder(Long userId, Long skuId, int price) { sleep(80); } private void sleep(long ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }

5.3 Controller

@RestController @RequestMapping("/order") public class OrderController { @Autowired private OrderService orderService; @PostMapping("/create") public String createOrder( @RequestParam Long userId, @RequestParam Long skuId) throws Exception { return orderService.createOrder(userId, skuId); } }

六、JMeter 压测与结果分析

6.1 压测配置说明

  • 并发线程数:200

  • Ramp-Up:1 秒


6.2 压测现象

  • 系统启动初期:

    • 接口 RT ≈288ms

  • 持续压测后:

    • RT 逐渐上升

    • 峰值约1888ms


6.3 原因分析

  1. 每个请求会向线程池提交3 个并行任务

  2. 200 个并发请求 ≈600 个线程池任务

  3. 线程池最大并发执行数为16

  4. 多余任务进入阻塞队列

  5. 队列满后触发CallerRunsPolicy

  6. 部分任务由HTTP 工作线程执行,导致请求处理时间变长


6.4 工程结论

  • RT 上升并不代表线程池失效

  • 这是线程池在高并发下的自我保护行为

  • 相比无限创建线程导致系统崩溃,RT 变慢是一种可接受的退化方式

线程池优化的是系统吞吐与稳定性,而不是在无限并发下保持恒定响应时间。

七、问题思考

7.1 为什么不用 @Async?

  • 难以进行复杂任务编排

  • 不利于精细化控制线程池

7.2 为什么不用 parallelStream?

  • 使用公共 ForkJoinPool

  • 线程资源不可控

7.3 线程池并非万能

  • 仍需配合限流、熔断等机制

  • 核心链路与非核心链路应区别对待

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 1:55:55

最新小程序 mtgsig1.2

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 部分python代码 cp execjs…

作者头像 李华
网站建设 2026/4/18 3:31:26

Termius中文版:移动端SSH连接的终极解决方案

还在为移动设备上的SSH连接操作而烦恼吗&#xff1f;Termius中文版为你带来全新的终端连接体验&#xff0c;让远程服务器管理变得前所未有的简单直观。 【免费下载链接】Termius-zh_CN 汉化版的Termius安卓客户端 项目地址: https://gitcode.com/alongw/Termius-zh_CN 项…

作者头像 李华
网站建设 2026/4/17 9:15:50

时序逻辑电路构建与测试:Multisim仿真项目应用

用Multisim玩转时序逻辑电路&#xff1a;从触发器到数字钟的完整仿真实践你有没有试过在面包板上搭一个计数器&#xff0c;结果数码管乱跳、进位丢失&#xff0c;查了半小时线路才发现是复位信号没处理好&#xff1f;或者写了一段Verilog代码烧进FPGA&#xff0c;发现状态机“抽…

作者头像 李华
网站建设 2026/4/18 3:26:05

新手避坑指南:部署Anything-LLM常见问题及解决方案

新手避坑指南&#xff1a;部署Anything-LLM常见问题及解决方案 在大语言模型&#xff08;LLM&#xff09;逐渐从实验室走向实际应用的今天&#xff0c;越来越多开发者和企业开始尝试将AI能力嵌入自己的工作流。然而&#xff0c;直接调用通用模型往往面临知识陈旧、缺乏上下文理…

作者头像 李华
网站建设 2026/4/18 2:53:12

Midscene.js实战指南:5个核心技巧帮你快速上手AI自动化测试

Midscene.js实战指南&#xff1a;5个核心技巧帮你快速上手AI自动化测试 【免费下载链接】midscene Let AI be your browser operator. 项目地址: https://gitcode.com/GitHub_Trending/mid/midscene 作为开发者&#xff0c;你是否曾经为重复的UI测试而烦恼&#xff1f;想…

作者头像 李华
网站建设 2026/4/17 19:06:44

图解说明:Altium Designer差分对布线中的PCB布局技巧

差分对布线实战指南&#xff1a;如何在Altium Designer中实现高质量PCB布局 你有没有遇到过这样的情况——电路板打样回来&#xff0c;高速信号误码率居高不下&#xff1f;眼看着时序匹配参数都“达标”了&#xff0c;EMI测试却依然超标。调试几天后才发现&#xff0c;问题出在…

作者头像 李华