ConcurrentHashMap 的 put 方法线程安全,JDK 8+ 采用 CAS + synchronized(锁桶首节点)实现细粒度并发控制,扩容亦并发安全,无需外部同步,但复合操作需用 putIfAbsent 等原子方法。

ConcurrentHashMap 的 put 方法本身是线程安全的,无需额外同步 —— 它通过分段锁(JDK 7)或 CAS + synchronized(JDK 8+)机制实现高效并发写入,关键在于**不依赖全局锁,而是对具体桶(bin)加锁或无锁操作**。
底层用细粒度锁或 CAS 保障单个桶的安全
JDK 8 及以后版本中,put 不再使用 Segment 分段锁,而是:
- 先通过哈希值定位到数组中的某个桶(
tab[i]) - 若桶为空,尝试用 CAS 原子地插入新节点 —— 成功则结束,失败说明有竞争,进入下一轮
- 若桶头节点已存在,则对该桶的首节点加
synchronized锁(锁的是链表头或红黑树根),再执行插入或替换逻辑 - 扩容时也通过 CAS 控制迁移状态,并发多个线程可协作完成,不阻塞读写
调用 put 时不需要手动加锁或同步
直接调用即可,例如:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key1", 100); // 线程安全,多线程同时调用没问题
只要不把 put 和其他非原子操作组合成“复合操作”,就无需额外保护。比如下面这种就**不是原子的**,仍需同步:
立即学习“Java免费学习笔记(深入)”;
if (!map.containsKey("key")) {
map.put("key", 1); // 这里存在竞态:检查和插入之间可能被其他线程插入
}
注意避免破坏线程安全的常见误用
-
不要在外部同步整个 map:如
synchronized(map) { map.put(...); },会严重降低并发性,还可能引发死锁 -
避免基于 get + put 的条件逻辑:应改用
putIfAbsent、computeIfAbsent、merge等原子方法 - key 和 value 自身需线程安全(如需):ConcurrentHashMap 保证容器操作安全,不保证 key/value 内部状态安全(比如 value 是 ArrayList,多线程修改它仍需同步)
扩容过程也是并发安全的
当 size 超过阈值,ConcurrentHashMap 会触发扩容。它不会一次性重建整个表,而是:
- 用一个 volatile 的
sizeCtl控制扩容状态和线程参与数 - 多个线程可协助迁移(helpTransfer),每个线程负责迁移一部分桶
- 迁移中读操作仍能正确返回(通过转发节点
ForwardingNode) - 写操作遇到正在迁移的桶,会先帮着迁移再插入

















