高并发扣减同一个商品库存时,你会用 synchronized 还是 ReentrantLock?锁粒度怎么定?
我的判断
库存扣减优先让数据库或库存服务做条件更新;JVM 锁只对单实例有效,选 synchronized 还是 ReentrantLock 反而是第二层问题。
如果多台应用同时扣同一个商品,本机锁挡不住其他实例。我会把正确性落在库存存储上,例如:
UPDATE sku_stock
SET available = available - 1
WHERE sku_id = ? AND available > 0;
根据受影响行数判断是否成功,并用业务请求号做幂等。热点很高时再通过分桶、排队或 Redis 预扣降低数据库竞争。
单进程内如果确实要保护共享对象,临界区短且只需要互斥,我会用 synchronized,语义简单、释放锁不容易写错;需要可中断、超时尝试或多个 Condition 时才用 ReentrantLock,并严格在 finally 解锁。
锁粒度通常按 skuId 做固定数量的条带,而不是每个商品永久创建一把锁,也不是锁整个扣库存方法。最终用热点商品压测观察等待时间、失败率和吞吐,不只验证库存没有负数。
思路拆解问题分析
这题容易一开始就在两种 Java 锁之间选边,但实际约束是 库存状态在哪里、是否多实例、失败是否会重试。锁只解决互斥,幂等、持久化和跨进程正确性必须另行处理。