concurrenthashmap通过分段锁、volatile变量、cas原子操作和分片计数实现高并发线程安全:读操作无锁,写操作仅锁单桶,扩容多线程协助,提供putifabsent等原子方法,size()返回近似值。

ConcurrentHashMap 能在保证线程安全的同时支撑高并发,核心在于它不锁整个表,而是通过分层控制、无锁读、细粒度写锁和原子操作协同实现——不是靠“更狠的锁”,而是靠“更少、更短、更聪明的同步”。
读操作几乎完全无锁
get、containsKey 等读方法全程不加锁。关键依赖:
- Node 节点的 val 和 next 字段都声明为 volatile,确保其他线程对值或链表结构的修改能立即被读线程看到;
- 哈希寻址(
hash & (table.length - 1))和遍历链表/红黑树的过程本身是纯计算,无共享状态竞争; - 即使读取过程中发生扩容或节点迁移,ConcurrentHashMap 也通过 ForwardingNode 等机制保证读操作总能获得一个一致(虽非实时最新)的结果。
写操作只锁定最小必要单元
put、remove 等写操作不再锁整个 Map,甚至不锁整个 Segment(JDK 8+ 已移除 Segment):
- 定位到具体桶(bin)后,仅对该桶的头节点加 synchronized 锁(例如锁住链表头 Node 或红黑树根 TreeNode);
- 同一桶内操作串行,但不同桶之间完全并行——100 个线程往 100 个不同 key 写入,基本互不影响;
- 扩容时采用多线程协助机制:一个线程触发扩容,其他线程在 put 时发现正在扩容,会主动帮助迁移部分桶,避免单点瓶颈。
复合逻辑靠原子方法保障,不靠手写同步
避免“先查再改”这类非原子组合引发竞态,ConcurrentHashMap 提供内置原子方法:
-
putIfAbsent(key, value):键不存在才插入,一次 CAS + 锁检查完成; -
computeIfAbsent(key, func):键不存在时才调用函数生成值,且整个过程线程安全,函数最多执行一次; -
merge(key, value, remappingFunc):存在则合并,不存在则插入,一步到位。
这些方法内部已封装了必要的同步与重试逻辑,比手动加锁或双重检查更简洁、更可靠。
计数与结构变更做异步/分片优化
像 size()、mappingCount() 这类全局统计操作,不阻塞写线程:
- 使用 LongAdder 思路的分段计数器(baseCount + counterCells 数组),写操作更新局部计数器,读时做汇总;
- 结果是近似实时值,但避免了为拿一个数字而锁全表;
- 实际业务中若需强一致性计数,应单独维护 LongAdder,而非依赖 size()。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











