ConcurrentHashMap 通过桶级锁、CAS无锁操作和volatile内存可见性实现线程安全:JDK 8+摒弃分段锁,仅对链表头或红黑树根节点加synchronized锁,多线程写不同桶完全并行;空桶插入等低竞争操作用CAS保证原子性;get全程无锁,依赖volatile读确保可见性。

ConcurrentHashMap 实现线程安全,不是靠一把大锁,而是通过分层控制 + 精细加锁 + 无锁读写的组合策略,在保障数据一致性的同时,把性能损耗压到最低。
核心是“桶级锁”而非“全表锁”
它放弃 Hashtable 那种对整个 map 加 synchronized 的粗粒度方式,也淘汰了 JDK 7 的 Segment 分段锁(16 段锁仍可能争抢同一段)。JDK 8+ 直接锁定数组中某个具体桶(即 `table[i]` 对应的链表头节点或红黑树根节点): - 多个线程往不同桶写入,完全不互斥 - 同一桶的写操作才需要同步,冲突概率大幅下降比如线程 A 往索引 3 插入,线程 B 往索引 15 插入,两者各自锁定自己的头节点,互不影响。
CAS 保证初始化和低竞争写入的原子性
很多关键步骤不用锁,改用底层 CAS 操作(Compare-And-Swap): - 表首次初始化:多个线程竞争执行 `initTable()`,仅一个能成功用 CAS 设置 `table` 数组 - 空桶插入新节点:直接 `casTabAt(tab, i, null, newNode)`,成功即写入,失败则重试 - 修改控制变量(如 `sizeCtl`):扩容阈值、线程计数等都靠 CAS 更新,避免锁开销CAS 是乐观策略——假设冲突少,先尝试,失败再退到锁机制,兼顾效率与正确性。
volatile 保障内存可见性
所有关键字段都用 `volatile` 修饰: - `transient volatile Node这确保一个线程对节点值或链表结构的修改,能立刻被其他线程看到,让无锁读操作(如 `get`)真正安全可靠——`get` 完全不加锁,只依赖 `volatile` 读取最新值。
立即学习“Java免费学习笔记(深入)”;
结构升级适配高并发场景
- 冲突少时:用普通链表(Node) - 链表长度 ≥ 8 且数组长度 ≥ 64 时:转为红黑树(TreeBin),查询从 O(n) 降为 O(log n) - 扩容中:插入 `ForwardingNode` 标记该桶正在迁移,读写线程可协作推进,不阻塞这些结构切换本身也由 CAS 和 synchronized 协同保护,不会出现中间态错乱。


















