ConcurrentHashMap 演进源于问题驱动:HashMap 线程不安全易成环或丢数据,Hashtable 全表锁性能差;JDK 1.7 用分段锁(Segment)提升并发度但粒度仍粗;JDK 1.8 改为桶级 synchronized + CAS + 红黑树,实现动态细粒度并发。

面试时讲 ConcurrentHashMap 演进,关键不是罗列版本,而是用“问题驱动”的逻辑串起来:每一代改进,都是为解决上一代暴露的痛点。下面这三句话就能锚定主线,后面展开自然清晰:
为什么必须演进?——HashMap 不行,Hashtable 太重
HashMap 在多线程下会出问题:JDK 1.7 扩容用头插法,多线程同时操作可能把链表变成环,get 一调就死循环、CPU 拉满;JDK 1.8 虽改用尾插法避免成环,但依然不保证线程安全,数据可能覆盖或丢失。而 Hashtable 给所有方法加同一把 synchronized 锁,相当于整张表只允许一个线程读或写,高并发时性能断崖式下跌。
JDK 1.7:用“分段锁”把大锁拆成小锁
核心是引入 Segment 数组(默认 16 个),每个 Segment 是一个继承 ReentrantLock 的小型 HashMap(内部是 HashEntry 数组 + 链表)。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 写操作时,先根据 key 的 hash 定位到某个 Segment,只锁它,其他 Segment 照常工作 → 并发度理论最高 16
- 读操作完全无锁,靠 volatile 修饰的 value 和 next 字段保证可见性
- 但 Segment 本身是粗粒度单位:哪怕两个 key 落在同一个 Segment 的不同桶里,也要排队等锁
JDK 1.8:放弃 Segment,锁直接落到“桶”上
底层结构和 HashMap 1.8 对齐:Node 数组 + 链表 + 红黑树,并发控制改用 CAS + synchronized 组合。
立即学习“Java免费学习笔记(深入)”;
- 数组初始化、扩容阈值更新等用 CAS,避免竞争
- 往空桶插入直接 CAS;非空桶则对链表头节点或红黑树根节点加 synchronized 锁 → 锁粒度细化到单个桶
- 链表长度 ≥ 8 且数组长度 ≥ 64 时转红黑树,防止长链表拖慢查询
- 扩容支持多线程协助:检测到正在扩容的桶(hash = MOVED),当前线程会主动帮着搬数据,不干等
一句话收尾:从 1.7 到 1.8,不是小修小补,是架构级重构——把“按段划分”的静态并发模型,升级为“按桶协作”的动态细粒度模型,更贴合现代多核 CPU 的并行特性。

















