JDK 1.8 桶级锁 + CAS,抛弃 Segment,直接 synchronized 锁单个首节点,冲突时才加锁;扩容时多线程协同迁移,CPU 利用率拉满。
一、前言
|
类 |
线程安全 |
并发度 |
备注 |
|
HashMap |
× |
—— |
最快,但多线程下 CPU 100% 死循环曾坑哭无数码农 |
|
Hashtable |
√ |
低 |
全表一把锁,基本等同于串行 |
|
Collections.synchronizedMap |
√ |
低 |
同上,只是包装器 |
|
ConcurrentHashMap |
√ |
极高 |
分段/桶级锁 + CAS,读写可并行,扩容亦并发 |
结论:并发场景下,CHM 是唯一“能扛流量又能打”的哈希表实现。
二、数据结构演进史
- JDK 1.5 分段锁(Segment)16 个可重入锁,理论并发度 16。
- JDK 1.8 桶级锁 + CAS抛弃 Segment,直接 synchronized 锁单个首节点,冲突时才加锁;扩容时多线程协同迁移,CPU 利用率拉满。
三、JDK 1.8 核心成员变量速览
// 位标识
staticfinalint MOVED = -1; // ForwardingNode
staticfinalint TREEBIN = -2; // 红黑树根
staticfinalint RESERVED = -3; // computeIfAbsent 占位
transientvolatile Node<K,V>[] table; // 主哈希桶
privatetransientvolatile Node<K,V>[] nextTable; // 扩容目标数组
privatetransientvolatilelong baseCount; // 无冲突时直接累加
privatetransientvolatileint sizeCtl; // 控制标识:负数=正在扩容/-1=初始化/n=扩容阈值
四、put 流程(含并发控制)
- 空表首次初始化通过 CAS 将 sizeCtl 从 0 改为 -1,单线程建表,其余线程 Thread.yield() 自旋等待。
- 计算哈希spread(key.hashCode()) 再散列,减少哈希碰撞。
- 定位桶(n - 1) & hash,与 HashMap 一致。
- 桶为空CAS 插入新节点,失败则自旋。
- 桶非空首节点 hash == MOVED → 帮忙扩容 (helpTransfer)。否则 synchronized 锁定首节点,再按链表/红黑树逻辑插入或更新。
- 计数 + 检查扩容addCount(1L, binCount),若超过 sizeCtl 则触发 transfer。
五、get 流程——全程无锁
- 计算哈希定位桶。
- 首节点匹配直接返回。
- 红黑树则按树查找;链表顺序遍历。
- 遇到 ForwardingNode 去 nextTable 重新查找。
可见性保障:Node.val 用 volatile 修饰;扩容时旧表只读,新表发布前通过 Unsafe 的 volatile 写保证。
六、扩容(transfer)——多线程协同搬运
- 步长 stride根据 CPU 核数计算每次迁移的桶数(最小 16),减少竞争。
- 全局进度索引 transferIndex从高位往低位分配任务包,CAS 抢占。
- 搬运算法对单个桶加 synchronized,构建新链表/树,插入到新表,旧桶头插 ForwardingNode 占位。
- 帮助扩容插入时发现 MOVED,当前线程领取stride步任务,加快迁移。
七、线程安全计数器
- baseCount:无竞争时直接累加。
- **CounterCell[]**:高并发时分散到数组,类似 LongAdder,最终 sumCount() 汇总。
八、红黑树与链表互转阈值
|
方向 |
阈值 |
说明 |
|
链表 → 树 |
8 |
且桶总数 ≥ 64,否则优先扩容 |
|
树 → 链表 |
6 |
删除节点后检查 |
九、实战踩坑指南
- 复合操作非原子
if (!map.containsKey(k)) map.put(k, v); // 仍有竞态
正确姿势:putIfAbsent(k, v) 或 computeIfAbsent。
- 遍历一致性Iterator 弱一致性:创建后其他线程增删改不抛 ConcurrentModificationException,但未必可见。
- 自定义对象作为 key必须保证不可变且正确实现 hashCode/equals,否则扩容前后定位桶不一致导致“幽灵丢失”。
- 批量操作forEach、search、reduce 支持并行化,可指定 parallelismThreshold,在大数据量场景比串行循环快 2~3 倍。
十、性能压测对比(1.8 vs 1.7 vs Hashtable)
测试场景:32 线程,各执行 1 千万次 put。
|
实现 |
耗时 (ms) |
吞吐量 (ops/us) |
|
Hashtable |
28 000 |
0.36 |
|
CHM 1.7 |
4 100 |
2.44 |
|
CHM 1.8 |
2 300 |
4.35 |
结论:1.8 桶级锁 + 协同扩容,比 1.7 分段锁再提 45%+。
十一、面试高频追问
- 为什么 1.8 放弃 Segment?粒度太粗,且维护 16 个数组指针占用内存;桶级锁已能满足极高并发。
- synchronized 性能差?1.8 对 synchronized 做了大量偏向锁/轻量锁优化,锁定时间极短(仅链表/树操作),CAS 失败概率低。
- CAS 自旋浪费 CPU?仅在空桶写入失败时自旋,冲突概率极低;扩容帮忙机制反而提升吞吐。
- 与 ConcurrentSkipListMap 区别?后者基于跳表,保证有序但 O(log n);CHM 无序 O(1),并发度更高。
AI大模型学习福利
作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
一、全套AGI大模型学习路线
AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取
二、640套AI大模型报告合集
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
三、AI大模型经典PDF籍
随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
四、AI大模型商业化落地方案

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量
211

被折叠的 条评论
为什么被折叠?



