用 concurrenthashmap 替代 hashmap 实现线程安全库存管理:键为商品标识(string),值为剩余数量(integer),使用 merge/computeifpresent 安全扣减,getordefault 判断可售,避免 null 和并发问题。

用 HashMap 存商品和库存量最直接
不需要数据库、不搞复杂分层时,HashMap<string integer></string> 就够用:键是商品编号或名称(String),值是剩余数量(Integer)。注意别用 int 做 value 类型——自动装箱/拆箱在并发或 null 场景下容易抛 NullPointerException。
常见错误是把库存当“状态”硬编码进类字段,结果每次增减都要改类结构。应该让数据可动态增删:
-
inventory.put("SKU001", 100)上架新商品 -
inventory.merge("SKU001", -1, Integer::sum)安全扣减(自动处理 key 不存在时的默认值) - 扣减前务必用
inventory.getOrDefault("SKU001", 0) > 0判断是否可售,别只靠 try-catch
多线程环境下必须加同步,但别盲目用 synchronized
如果系统有多个出库线程(比如模拟秒杀或后台定时任务),HashMap 会 ConcurrentModificationException 或读到脏数据。此时不是简单给方法加 synchronized 就完事:
- 用
ConcurrentHashMap替代HashMap,它支持高并发读、安全的computeIfPresent扣减 - 避免在同步块里做 I/O(如打印日志、调远程接口),否则整个库存操作被拖慢
- 如果业务要求“扣减+记录日志”原子性,得用
ReentrantLock配合 try-finally,而不是依赖 synchronized 方法锁
库存预警和归零逻辑不能只靠 if 判断
单纯写 if (stock 在并发场景下会漏报或重复告警。真正实用的做法是:
立即学习“Java免费学习笔记(深入)”;
- 用
AtomicInteger包装库存值,配合getAndDecrement()或compareAndSet()实现条件触发 - 把“低于阈值”变成一次性的状态变更:比如首次降到 5 时设个
lowStockNotified标志位(也用AtomicBoolean) - 归零后仍要允许“补货”,所以不要删掉 key,而是保持
inventory.put("SKU001", 0),否则merge会误判为新商品
测试时别忘了边界:负库存、超卖、空字符串商品 ID
真实业务里,前端传参可能带空格、null 或负数,Java 层必须拦截:
-
Objects.requireNonNull(productId, "商品ID不能为空")比if (id == null)更明确抛什么错 - 扣减数量传入负数?直接 throw
IllegalArgumentException,别让它走到 map 操作里 - 用
String.trim().isEmpty()清洗商品 ID,否则"A001 "和"A001"被当两个商品 - JUnit 测试要覆盖
inventory.get("MISSING_ID") == null场景,别假设所有 key 都存在
集合本身不解决业务规则,比如“不同仓库独立库存”或“预售锁定量”,这些得靠额外字段或拆成多个 map。别指望一个 HashMap 扛下所有现实约束。









