ConcurrentHashMap 的 get 方法无锁且线程安全:仅读取,不修改结构;volatile 保证 val、next 和 table 可见性;final 确保 key 和 hash 不变;写操作锁定单桶,读写天然隔离。

get 是纯读操作,不改变任何共享状态
ConcurrentHashMap 的 get 方法只做查找,不修改 table、不调整链表或红黑树结构、不触发扩容、也不变更节点指针。整个流程就是:算 hash → 定位桶 → 检查首节点 → 匹配则返回值 → 否则顺着 next 往下遍历。没有写入,就没有竞态条件,自然无需加锁。
volatile 保证关键字段的可见性
Node 的 val 和 next 字段都是 volatile 修饰的,table 数组引用本身也是 volatile 的。这意味着:
- 一个线程 put 成功写入 val,其他线程的 get 立刻能看到新值;
- 扩容时新 table 赋值后,所有线程的 get 都能立即感知并转向新表;
- 链表插入新节点后,next 指针更新对读线程可见,不会遍历到“半初始化”节点。
final 保障 key 和 hash 不可变
Node 中的 hash 和 key 是 final 字段,构造完成后不可更改。get 过程中比对 key 时,完全不用担心另一个线程正在改写它——这种设计从根源上消除了读取过程中 key 被篡改的风险,也避免了额外同步的需要。
写操作与读操作天然隔离
put/remove 等写操作只锁定单个桶的首节点(synchronized on first),且仅在结构性修改时才加锁。而 get 始终读取当前已存在的节点视图:
立即学习“Java免费学习笔记(深入)”;
- 写线程在插入新节点,读线程看到的是旧链表,两者互不干扰;
- 遇到 ForwardingNode(扩容中),get 会自动跳转到新表继续查找,逻辑封装在 find() 内,仍无锁;
- 遍历红黑树时调用 TreeBin.find(),内部虽有轻量级读锁,但那是 TreeBin 自己的协调机制,不属于 ConcurrentHashMap 层面的加锁。


















