ConcurrentHashMap 的设计在 JDK 7 与 JDK 8 差异很大。
JDK 7 用分段锁(Segment 数组,类似可重入锁的 HashTable 分片):每个 Segment 独立加锁,默认 16 段即支持 16 并发写;缺点是 Segment 数组创建后不可扩容,锁粒度仍较粗。
JDK 8 废弃分段锁,结构与 HashMap 一致(数组+链表+红黑树),改用更细粒度的并发控制:插入空桶时用 CAS 无锁写入;桶非空时用 synchronized 锁住该桶的头节点——锁粒度精确到单个桶,不同桶的写操作完全并发;配合 volatile 保证数组引用和 Node 的 val/next 的可见性;读操作完全无锁(依赖 volatile 的 happens-before 保证读到最新值)。扩容支持多线程协同:正在扩容时其他线程遇到 ForwardingNode 会帮忙搬运数据。
size 统计用类似 LongAdder 的分段计数(baseCount + CounterCell 数组),避免单点竞争。
要点:不允许 null key/null value(避免二义性:get 返回 null 无法区分"不存在"与"值为 null");复合操作(putIfAbsent、compute)本身是原子的,但跨方法调用仍需额外同步。
追问方向:为什么不用 ReentrantLock 而回退 synchronized?(JVM 锁优化:偏向锁/轻量级锁已大幅降低成本)
(约 380 字)