ConcurrentHashMap 采用分段锁(JDK7)或CAS+synchronized单桶锁(JDK8+)实现高并发,底层为数组+链表+红黑树,get无锁、put/remove细粒度加锁,不支持null键值,迭代器弱一致性。

ConcurrentHashMap 的核心设计思想
ConcurrentHashMap 不是靠锁整个 Map 来保证线程安全,而是采用“分段锁”(JDK 7)或“CAS + synchronized 锁单个桶”(JDK 8+)的方式,把并发冲突控制在更小粒度上。它允许多线程同时读写不同位置的数据,大幅提升并发吞吐量。
JDK 8 中的底层结构:数组 + 链表 + 红黑树
底层是一个 Node 数组,每个数组元素(即“桶”)是一个链表或红黑树的头节点。插入时先通过 hash 定位到桶,再根据以下策略处理:
- 桶为空:用 CAS 尝试插入新节点
- 桶已存在节点:对首节点加 synchronized 锁(仅锁该桶,不影响其他桶)
- 链表长度 ≥ 8 且数组长度 ≥ 64:触发树化,转为红黑树提升查找效率
- 红黑树节点数 ≤ 6:退化回链表
关键操作的线程安全性保障
get 操作完全无锁,依赖 volatile 语义保证可见性;put、remove 等写操作则结合 CAS 和细粒度锁实现原子性:
本书是全面讲述PHP与MySQL的经典之作,书中不但全面介绍了两种技术的核心特性,还讲解了如何高效地结合这两种技术构建健壮的数据驱动的应用程序。本书涵盖了两种技术新版本中出现的最新特性,书中大量实际的示例和深入的分析均来自于作者在这方面多年的专业经验,可用于解决开发者在实际中所面临的各种挑战。
- put(K,V):先尝试 CAS 插入头节点;失败则锁住桶首节点,再遍历链表/树判断是否已存在 key,决定更新还是新增
- computeIfAbsent(K, mappingFunction):只在 key 不存在时调用函数生成 value,并确保整个过程线程安全
- size() 和 mappingCount():不直接遍历全表,而是维护 baseCount + CounterCell[] 数组,通过分散计数减少竞争
使用注意事项与常见误区
ConcurrentHashMap 并非万能,需注意其行为边界:
立即学习“Java免费学习笔记(深入)”;
- 不支持 null 作为 key 或 value(会抛 NullPointerException)
- 迭代器弱一致性:遍历时可能反映某次操作的中间状态,但不会抛 ConcurrentModificationException
- 批量操作如 forEach、search、reduce 等,内部按段并行执行,结果取决于执行时刻的快照
- 不要用它替代同步逻辑复杂的业务场景(比如需要多个 key 原子性更新),应配合显式锁或事务机制









