网站首页 > 博客文章 正文
一、秒杀场景的致命挑战
问题:10000人抢100件商品,如何避免超卖?
核心难点:
- 高并发:QPS 破万,传统数据库锁直接崩溃。
- 超卖:库存扣减顺序错乱,导致库存减为负数。
二、JUC 解决方案对比
方案 | 原理 | 优点 | 缺点 |
synchronized | 悲观锁,独占资源 | 简单易用 | 性能差(线程阻塞) |
ReentrantLock | 显式锁,可中断/公平锁 | 灵活控制 | 需手动释放锁 |
AtomicLong | CAS 无锁更新 | 高性能、无阻塞 | 高并发下CAS自旋开销大 |
LongAdder | 分段CAS + 最终求和 | 极致性能 | 实时性略低 |
三、实战代码:4种方案压测对比
场景:模拟10000人抢100件商品,对比成功率与性能。
1. synchronized 方案(灾难级)
public class SyncStockService {
private int stock = 100;
public synchronized boolean deductStock() {
if (stock > 0) {
stock--;
return true;
}
return false;
}
}
// 压测结果:QPS ≈ 500,超卖率0%,但性能极差!
2. ReentrantLock 方案(改进版)
public class LockStockService {
private int stock = 100;
private final ReentrantLock lock = new ReentrantLock();
public boolean deductStock() {
lock.lock();
try {
if (stock > 0) {
stock--;
return true;
}
return false;
} finally {
lock.unlock();
}
}
}
// 压测结果:QPS ≈ 2000,无超卖,但锁竞争仍是瓶颈。
3. AtomicLong CAS 方案(无锁优化)
public class AtomicStockService {
private final AtomicLong stock = new AtomicLong(100);
public boolean deductStock() {
long current = stock.get();
if (current <= 0) return false;
return stock.compareAndSet(current, current - 1); // CAS更新
}
}
// 压测结果:QPS ≈ 8000,但高并发下大量线程自旋导致CPU飙升!
4. LongAdder 方案(终极版)
public class LongAdderStockService {
private final LongAdder stock = new LongAdder();
public LongAdderStockService() {
stock.add(100); // 初始化库存
}
public boolean deductStock() {
if (stock.sum() <= 0) return false; // 实时性要求不高时使用
stock.decrement(); // 分段CAS减少竞争
return true;
}
}
// 压测结果:QPS > 20000,无超卖,CPU平稳!
四、性能压测报告(JMH测试)
方案 | QPS | 超卖率 | CPU占用 |
synchronized | 512 | 0% | 90% |
ReentrantLock | 2100 | 0% | 70% |
AtomicLong | 8500 | 0% | 100% |
LongAdder | 23000 | 0% | 40% |
结论:
单机场景:LongAdder 是性能王者,分段CAS碾压其他方案。
实时性要求高:用 AtomicLong(但需监控CPU)。
五、分布式场景扩展
单机方案无法解决集群问题!分布式场景推荐:
- Redis + Lua 脚本:原子扣减库存。
if redis.call('get', KEYS[1]) >= 1 then
return redis.call('decr', KEYS[1])
end
- RocketMQ 削峰:请求入队,异步扣减。
六、避坑指南
- AtomicLong 的陷阱:
// 错误用法:先检查再操作仍可能超卖!
if (atomic.get() > 0) {
atomic.decrementAndGet(); // 非原子操作!
}
正确写法:必须用 CAS 循环!
long current;
do {
current = atomic.get();
if (current <= 0) return false;
} while (!atomic.compareAndSet(current, current - 1));
- LongAdder 的代价:
- sum() 方法实时性差(合并分段值有延迟),适合最终一致性场景。
七、总结
- 单机:LongAdder > AtomicLong > ReentrantLock > synchronized。
- 分布式:Redis原子操作 + MQ削峰填谷。
- 黄金准则:
- 能用无锁,就不用加锁;
能分段,就不要硬刚!
代码决定下限,架构决定上限。
下期预告:《Redis+Lua:分布式锁的7大陷阱》—— 关注我,解锁更多高并发干货!
猜你喜欢
- 2025-07-21 开源|一款类excel报表设计系统,支持拖拽式和word模板设计
- 2025-07-21 SpringBoot利用ThreadPoolTaskExecutor批量插入百万级数据实测!
- 2025-07-21 云端藏经阁:一款开源、精美、可独立部署的知识管理神器
- 2025-07-21 简单易用的.NET免费开源RabbitMQ操作组件EasyNetQ
- 2025-07-21 亿级分库分表,如何丝滑扩容、如何双写灰度
- 2025-07-21 使用mq实现分布式事务-补偿事务一致性
- 2025-07-21 【RocketMQ】消息的拉取(rocketmq消息大小)
- 2025-07-21 RocketMQ消息消费-客户端拉取消息前的准备工作
- 2025-07-21 RocketMQ消费限流的几种方式(rocketmq并发消费与顺序消费)
- 2025-07-21 Spring Boot 3 中如何整合 RocketMQ 实现消息队列处理
你 发表评论:
欢迎- 07-21谷歌云发生全球范围大规模宕机(谷歌云什么时候上线的)
- 07-21谷歌云全球崩盘!OpenAI Shopify瘫痪,万亿级服务为何一夜失灵?
- 07-21国泰君安:谷歌云的利润率大超预期,AI投资的回报正逐步显现
- 07-21谷歌云技术故障引发全球互联网服务大瘫痪
- 07-21谷歌发生长达数小时云服务宕机事件,全球超70项谷歌云服务停止正常运行!谷歌致歉并发布事故报告
- 07-21开源|一款类excel报表设计系统,支持拖拽式和word模板设计
- 07-21SpringBoot利用ThreadPoolTaskExecutor批量插入百万级数据实测!
- 07-21云端藏经阁:一款开源、精美、可独立部署的知识管理神器
- 最近发表
-
- 谷歌云发生全球范围大规模宕机(谷歌云什么时候上线的)
- 谷歌云全球崩盘!OpenAI Shopify瘫痪,万亿级服务为何一夜失灵?
- 国泰君安:谷歌云的利润率大超预期,AI投资的回报正逐步显现
- 谷歌云技术故障引发全球互联网服务大瘫痪
- 谷歌发生长达数小时云服务宕机事件,全球超70项谷歌云服务停止正常运行!谷歌致歉并发布事故报告
- 开源|一款类excel报表设计系统,支持拖拽式和word模板设计
- SpringBoot利用ThreadPoolTaskExecutor批量插入百万级数据实测!
- 云端藏经阁:一款开源、精美、可独立部署的知识管理神器
- 电商秒杀/库存扣减:基于JUC的并发控制实战案例
- 简单易用的.NET免费开源RabbitMQ操作组件EasyNetQ
- 标签列表
-
- ifneq (61)
- 字符串长度在线 (61)
- googlecloud (64)
- flutterrun (59)
- 系统设计图 (58)
- powershellfor (73)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- qcombobox样式表 (68)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)