news 2026/6/23 16:35:42

ConcurrentHashMap从分段锁到CAS+synchronized

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ConcurrentHashMap从分段锁到CAS+synchronized

🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐➕关注👀是作者创作的最大动力🤞

💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝+关注👀欢迎留言讨论

🔥🔥🔥(源码获取 + 调试运行 + 问题答疑)🔥🔥🔥 有兴趣可以联系我

🔥🔥🔥 文末有往期免费源码,直接领取获取(无删减,无套路)

我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。

🔥🔥🔥(免费,无删减,无套路):java swing管理系统源码 程序 代码 图形界面(11套)」
链接:https://pan.quark.cn/s/784a0d377810
提取码:见文章末尾

从分段锁到CAS+synchronized:JDK8 ConcurrentHashMap的全面进化

引言:并发容器演进的分水岭

在Java并发编程的演进历程中,JDK8对ConcurrentHashMap的重构无疑是里程碑式的事件。这次重构不仅仅是性能的提升,更是设计哲学的根本转变。从JDK1.7的分段锁到JDK8的CAS+synchronized,ConcurrentHashMap完成了从"粗粒度并发控制"到"细粒度无锁化"的华丽转身。

一、数据结构革命:从分段数组到数组+链表/红黑树

JDK1.7:Segment分段锁架构

JDK1.7的ConcurrentHashMap采用二级哈希结构:

  • 外层:Segment数组,每个Segment继承ReentrantLock

  • 内层:HashEntry数组,存储实际的键值对

// JDK1.7结构示意 ConcurrentHashMap { Segment[] segments; // 固定16个分段 ↓ Segment { HashEntry[] table; // 分段内的哈希表 ReentrantLock lock;// 分段锁 } }

这种设计的先天缺陷

  1. 锁粒度固定:并发度受限于Segment数量(默认16)

  2. 内存开销大:每个Segment都继承ReentrantLock,包含复杂的锁状态管理

  3. 查询效率低:两次哈希计算,链表过长时性能急剧下降

🔥🔥🔥(免费,无删减,无套路): Python源代码+开发文档说明(23套)」
链接:https://pan.quark.cn/s/1d351abbd11c
提取码:见文章末尾

🔥🔥🔥(免费,无删减,无套路):计算机专业精选源码+论文(26套)」
链接:https://pan.quark.cn/s/8682a41d0097
提取码:见文章末尾
🔥🔥🔥(免费,无删减,无套路):Java web项目源码整合开发ssm(30套)
链接:https://pan.quark.cn/s/1c6e0826cbfd
提取码:见文章末尾

🔥🔥🔥(免费,无删减,无套路):「在线考试系统源码(含搭建教程)」

链接:https://pan.quark.cn/s/96c4f00fdb43
提取码:见文章末尾

JDK8:数组+链表/红黑树混合结构

JDK8彻底抛弃分段锁,回归经典的哈希表结构:

  • 单层Node数组,元素为Node对象

  • 链表长度>8且数组长度≥64时,链表转换为红黑树

  • 红黑树节点数<6时,退化为链表

这一改进带来的核心优势

  1. 更接近最优哈希表:减少一次哈希计算

  2. 动态树化:有效解决哈希冲突导致的性能问题

  3. 内存更紧凑:去除了Segment的额外开销

二、并发控制进化:从分段锁到CAS+synchronized

JDK1.7:粗粒度锁控制

每个Segment独立加锁,同一时刻最多16个线程可并发写入(默认配置)。虽然比Hashtable的全局锁有进步,但仍有明显限制:

  • 不同Segment上的操作不互斥

  • 同一Segment上的操作完全互斥

  • 读操作也需要获取Segment的轻量级锁

JDK8:精细化无锁化策略

JDK8采用分层并发控制策略:

1. 无锁化的读操作

读操作完全无锁,通过volatile保证可见性:

public V get(Object key) { Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek; int h = spread(key.hashCode()); if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n - 1) & h)) != null) { // 直接读取,无需加锁 if ((eh = e.hash) == h) { if ((ek = e.key) == key || (ek != null && key.equals(ek))) return e.val; } // 特殊处理:ForwardingNode或TreeBin else if (eh < 0) return (p = e.find(h, key)) != null ? p.val : null; // 遍历链表 while ((e = e.next) != null) { if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) return e.val; } } return null; }
2. 精细化的写锁

写锁精确到桶级别:

  • 空桶:CAS插入

  • 非空桶:synchronized锁定链表头节点

final V putVal(K key, V value, boolean onlyIfAbsent) { // ... synchronized (f) { // 只锁住当前桶的头节点 if (tabAt(tab, i) == f) { // 链表或树操作 } } // ... }
3. 扩容时的协作机制

通过ForwardingNode实现多线程协助扩容,将扩容时间分摊到多个线程。

三、性能对比:多维度的全面超越

3.1 并发度对比

维度JDK1.7JDK8
最大写并发固定(默认16)理论上等于桶数量
读并发有限制(需获取读锁)完全无锁
锁竞争分段内竞争桶级别竞争

3.2 内存使用对比

JDK1.7内存开销

  • 16个Segment对象

  • 每个Segment包含一个ReentrantLock

  • 额外的锁状态管理字段

JDK8内存优化

  • 去除了Segment层级

  • 锁对象复用(桶头节点作为锁对象)

  • 更紧凑的内存布局

3.3 操作性能对比

写操作

  • JDK1.7:需要获取Segment锁,竞争激烈时性能下降

  • JDK8:CAS或桶级别锁,冲突范围大幅缩小

读操作

  • JDK1.7:需要获取Segment的共享锁

  • JDK8:完全无锁,性能接近HashMap

扩容操作

  • JDK1.7:整个Segment锁定进行扩容

  • JDK8:多线程协助,渐进式扩容

四、核心技术改进详解

4.1 CAS操作的广泛应用

JDK8中CAS不再只是简单的计数器,而是贯穿整个设计:

  1. 表初始化:通过sizeCtl控制

  2. 桶插入:空桶使用CAS

  3. 计数更新:baseCount和CounterCell

  4. 扩容控制:transferIndex分配任务

4.2 红黑树优化

链表转红黑树的阈值(8)和红黑树转链表的阈值(6)经过精心设计,避免频繁转换:

  • 树化代价高,需要慎重

  • 退化为链表避免空间浪费

  • TreeBin封装红黑树,同时维护链表顺序支持读操作

4.3 协助式扩容机制

传统HashMap扩容时整个表被锁定,而ConcurrentHashMap通过精巧的设计实现并行扩容:

  1. ForwardingNode标记:已迁移的桶放置特殊节点

  2. 逆序迁移:从后向前处理,避免冲突

  3. 任务分配:多个线程协作完成迁移

4.4 分散式计数机制

借鉴LongAdder思想,解决高并发下的计数瓶颈:

  • baseCount:低竞争时的快速路径

  • CounterCell数组:高竞争时的分散计数

  • @Contended注解:防止伪共享

五、设计哲学的变化

从"防御性并发"到"乐观并发"

JDK1.7哲学:假设冲突是常态,预先分配锁资源

  • 预先创建16个Segment

  • 读写都需要获取锁

  • 设计偏保守

JDK8哲学:假设冲突是特例,乐观处理冲突

  • 无锁读取是默认路径

  • CAS失败才加锁

  • 按需创建同步结构

从"静态分区"到"动态适应"

JDK1.7:静态的16分区,无法根据实际情况调整JDK8:动态的桶级别锁,完全根据哈希分布自适应

从"锁为中心"到"无锁优先"

这一转变反映了并发编程的发展趋势:

  1. 硬件发展:CAS操作得到CPU更好支持

  2. 理论成熟:无锁算法研究深入

  3. 需求变化:高并发成为常态而非特例

六、实际应用启示

6.1 选择时机

  • JDK8+环境:默认使用JDK8的ConcurrentHashMap

  • 兼容性要求:如果需要兼容JDK7,考虑降级方案

6.2 最佳实践

  1. 预分配容量:避免频繁扩容

  2. 合理哈希:保证键的哈希质量

  3. 监控树化:过多的树节点可能指示哈希函数问题

6.3 性能调优

  • 关注sizeCtl的调整

  • 监控CounterCell竞争情况

  • 分析红黑树与链表的比例

七、未来展望

JDK8的ConcurrentHashMap设计已经相当成熟,但仍有优化空间:

  1. 更智能的树化策略:基于运行时统计动态调整阈值

  2. 更好的内存局部性:优化节点排列

  3. 更灵活的并发控制:自适应锁策略

结论

从JDK1.7到JDK8,ConcurrentHashMap的演进是Java并发编程发展的缩影。这次重构不仅仅是技术的升级,更是设计理念的飞跃。它告诉我们:

  1. 细粒度优于粗粒度:更精确的控制带来更好的并发性

  2. 无锁优于有锁:乐观并发是高性能的基石

  3. 自适应优于静态:动态调整能更好地应对多变场景

ConcurrentHashMap的成功重构,为我们在设计高并发系统时提供了宝贵经验:在保证线程安全的前提下,尽可能减少同步,让并发操作"轻装前进"。这种思想,正是现代高性能系统设计的核心要义。

JDK1.7 vs JDK8 ConcurrentHashMap架构对比

JDK8 ConcurrentHashMap核心操作流程


往期免费源码对应视频:

免费获取--SpringBoot+Vue宠物商城网站系统

🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐➕关注👀是作者创作的最大动力🤞

💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝+关注👀欢迎留言讨论

🔥🔥🔥(源码 + 调试运行 + 问题答疑)

🔥🔥🔥 有兴趣可以联系我

💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!

💖常来我家多看看,
📕网址:扣棣编程
🎉感谢支持常陪伴,
🔥点赞关注别忘记!

💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!

⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇点击此处获取源码⬇⬇⬇⬇⬇⬇⬇⬇⬇

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/24 2:54:50

Ascend C 高阶编程艺术:多核协同、流水线调度与异构任务编排实战

引言&#xff1a;从“单算子优化”到“系统级性能工程”在掌握 Ascend C 基础算子开发后&#xff0c;许多开发者会遇到新的瓶颈&#xff1a;即使单个算子已极致优化&#xff0c;端到端推理延迟仍不理想。问题往往出在 任务调度、数据流转、多核协作 等系统层面。昇腾 AI 处理器…

作者头像 李华
网站建设 2026/6/24 0:38:48

震惊!Linux开发板稳定性排行,这家竟碾压群雄!

Linux开发板稳定性排行揭晓&#xff0c;这家企业竟碾压群雄&#xff01;在当今数字化浪潮中&#xff0c;Linux开发板作为嵌入式系统的核心组件&#xff0c;其稳定性直接关系到工业自动化、智能家居、物联网终端等关键应用的可靠性。市场上各类开发板品牌林立&#xff0c;性能参…

作者头像 李华
网站建设 2026/6/23 13:59:28

Day37 模型可视化与推理

一、模型可视化 1. nn.model自带的方法 # nn.Module 的内置功能&#xff0c;直接输出模型结构 print(model) MLP((fc1): Linear(in_features4, out_features10, biasTrue)(relu): ReLU()(fc2): Linear(in_features10, out_features3, biasTrue) ) # nn.Module 的内置功能&a…

作者头像 李华
网站建设 2026/6/23 3:17:34

n8n第十节 把Markdown格式的会议纪要发到企微

朋友们&#xff0c;有没有感觉整理纪要格式很乱&#xff0c;发到企微群里还得截图&#xff0c;别人看着也费劲。今天教你——用n8n工作流&#xff0c;把AI生成的Markdown格式会议纪要&#xff0c;原汁原味直接发到企业微信&#xff01;最大亮点&#xff1a;直接传Markdown格式&…

作者头像 李华
网站建设 2026/6/23 2:09:05

鸡排哥申请个体户,商标名称10年前已被注册!

近日鸡排哥&#xff08;本名李俊永&#xff09;是在江西景德镇因炸鸡排走红的草根摊主&#xff0c;近日注册成立景德镇市珠山区李俊永餐饮管理工作室&#xff0c;经营范围涵盖餐饮管理、食品销售。普推知产商标老杨检索发现&#xff0c;“鸡排哥”在2015年已有上海公司申请注册…

作者头像 李华