秒杀场景必须用线程池做异步排队,因瞬时高并发会压垮mysql,线程池通过有界队列+定长线程实现流量削峰、可控执行与自然限流,并需配合redis预校验、幂等设计及异步通知等机制。

秒杀场景下为什么必须用线程池做异步排队
高并发秒杀时,瞬时流量可能达数万QPS,若所有请求都同步走数据库扣库存、写订单,MySQL极易被打爆,出现超时、死锁甚至宕机。线程池不是“锦上添花”,而是把洪峰流量接住、削平、缓冲的关键一环——它把下单请求从“立即执行”转为“排队+有限并发执行”,让系统可控、可降级、不雪崩。
核心设计:用阻塞队列 + 定长线程池实现可控排队
推荐使用 LinkedBlockingQueue(有界)搭配 FixedThreadPool,避免内存溢出和无序堆积:
- 队列要有界:例如设置容量为 2000,超出直接拒绝(返回“排队中,请稍候”或降级为异步短信通知),防止OOM
- 线程数要合理:通常设为 CPU 核数 × 2 ~ 4(如 8 核机器配 16~32 线程),过高反而引发上下文切换开销
- 拒绝策略选 CallerRunsPolicy:当队列满且线程忙时,由调用方(Web线程)自己执行任务,自然限流,避免丢弃关键请求
订单异步处理的典型代码结构
以 Spring Boot 为例,定义一个线程安全的秒杀任务处理器:
// 1. 配置线程池 Bean(推荐放在 @Configuration 类中)
@Bean("seckillTaskExecutor")
public Executor seckillTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(2000);
executor.setThreadNamePrefix("seckill-task-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
// 2. 秒杀接口中提交任务(不等待结果)
@PostMapping("/seckill/{itemId}")
public Result seckill(@PathVariable Long itemId, @RequestBody SeckillRequest req) {
// 校验用户、库存预检查(Redis计数器)、幂等性(防重复提交)
if (!redisTemplate.opsForValue().decrement("stock:" + itemId).intValue() > 0) {
return Result.fail("库存不足");
}
// 构建异步任务(含用户ID、商品ID、订单号等上下文)
SeckillTask task = new SeckillTask(req.getUserId(), itemId, IdUtil.fastSimpleUUID());
seckillTaskExecutor.execute(() -> processSeckillOrder(task));
return Result.success("已进入排队,请关注订单状态");
}
// 3. 真正的订单落地逻辑(在独立线程中执行)
private void processSeckillOrder(SeckillTask task) {
try {
// 1. 再次校验库存(DB层面 for update 或 Redis Lua 原子扣减)
// 2. 插入订单主表(带唯一索引防重)
// 3. 更新订单状态、发MQ通知履约服务
// 4. 记录操作日志 & 监控埋点
} catch (Exception e) {
// 记录错误,可补偿(如回滚Redis库存、发告警)
log.error("秒杀订单处理失败", e);
redisTemplate.opsForValue().increment("stock:" + task.getItemId()); // 补库存
}
}
必须配合的配套机制
单靠线程池不够,需组合以下能力才能真正稳住秒杀链路:
- 前置缓存校验:用 Redis 做库存原子扣减(Lua脚本)和用户限购判断,99% 请求在缓存层拦截
- 唯一订单号 + 幂等表:防止同一请求因重试多次落库,插入前先查幂等表
- 异步结果通知:通过 WebSocket 或轮询接口告知用户“下单成功/失败”,不要同步等 DB 返回
- 监控与熔断:实时看线程池活跃数、队列积压、拒绝率;超过阈值自动关闭秒杀入口(Sentinel 或自定义开关)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











