1. 问题背景:电商库存并发Bug的诡异现象
上周团队里一个刚工作两年的小伙子遇到了一个让他抓狂的问题:电商系统的库存扣减出现了诡异的重复扣减。明明日志里显示一切正常,但实际运行时两个订单同时扣减了同一件商品的最后一件库存。更让人崩溃的是,查日志时每条记录看起来都完全合理,没有任何异常。
这种情况在电商系统中其实很常见,特别是在大促期间。库存只有1件,两个用户同时下单,系统竟然都判定库存充足并完成了扣减。从业务角度看这显然是严重问题,但从日志层面却找不到任何破绽。
提示:这种"日志看起来一切正常但实际业务出问题"的情况,往往是并发问题的典型特征。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 并发Bug的本质:为什么日志无法还原真相
2.1 从代码层面看问题
让我们先看一个简化版的库存服务代码:
java复制@Service
public class StockService {
private int stock = 1; // 共享变量,初始库存为1
public void createOrder() {
log.info("当前库存: {}", stock); // 日志1
if (stock > 0) { // 检查库存
stock--; // 扣减库存
log.info("扣减库存成功,剩余库存: {}", stock); // 日志2
} else {
log.warn("库存不足");
}
}
}
这段代码在单线程环境下运行完全没问题,但在并发场景下就会出现严重问题。问题出在"检查-执行"这个复合操作不是原子的。
2.2 并发执行的时间线分析
让我们用时间线表格来还原两个线程并发执行时的真实情况:
| 时间点 | 线程A操作 | 线程B操作 | 内存中的stock值 | 日志输出 |
|---|---|---|---|---|
| t1 | 读取stock=1 | - | 1 | 线程A: 当前库存:1 |
| t2 | - | 读取stock=1 | 1 | 线程B: 当前库存:1 |
| t3 | stock-- (1→0) | - | 0 |
