Software Engineer · 语言与工程基础

ConcurrentHashMap:线程安全为何仍需原子复合操作

解释并发 map 的可见性、复合更新、迭代语义与跨键事务边界。

题目重点:解释并发 map 的可见性、复合更新、迭代语义与跨键事务边界。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 以 Java 21 API 为参考;实现版本不同,不统一称为分段锁。

解题路线

  1. 单个 map 操作线程安全,但 get 后 put 是两个操作。计数使用 merge/compute 或合适的原子值,避免丢更新。
  2. 常见现代实现结合桶级协调和 CAS 等技术;解释热点桶与扩容协作,不把实现细节当永久规范。
  3. get 通常不阻塞,迭代弱一致而非冻结快照;size 在并发更新时不适合作为精确控制条件。不允许 null 键和值。
  4. compute 回调应短小,不在内做网络 I/O 或递归修改相关映射。跨两个键的守恒约束不是自动事务,需要额外协调。

手动走一遍

两个线程都读取0然后各 put1,最终只有1;merge(k,1,Integer::sum) 按该键原子更新能保留两次增量。从 A 扣钱再给 B 加钱即便各自 compute,也会存在中间状态;转账合同需要一体事务。

规模与取舍

良好散列下查找通常平均 O(1),热点键限制并发吞吐。大型 map 的遍历与内存成本仍随规模增长。

易错点与追问

容易失分的边界

  • 线程安全容器保证任意多步算法原子。
  • size 精确快照。
  • 在 compute 里执行慢远程请求。

继续深挖

  • LongAdder 适合计数但适合精确限额吗?
  • 如何获取一致快照?

技术参考

✓已复制微信号!