当前位置: 首页 > backend >正文

java8 ConcurrentHashMap 桶级别锁实现机制

Java 8 ConcurrentHashMap 桶级别锁实现机制

Java 8 中的 ConcurrentHashMap 抛弃了分段锁设计,采用了更细粒度的桶级别锁(bucket-level locking)实现,这是其并发性能提升的关键。下面详细解析其实现原理:

1. 基本实现原理

桶级别锁的核心思想是:只锁定当前操作的哈希桶(链表或树的头节点),而不是整个表或某个段。

关键实现方式:

  • CAS + synchronized 组合控制
  • 锁对象是每个桶的头节点
  • 读操作完全无锁(volatile读)
  • 写操作仅在必要时加锁

2. 具体实现细节

2.1 锁获取方式

// putVal方法中的锁获取片段
synchronized (f) { // f是桶的头节点if (tabAt(tab, i) == f) { // 双重检查// 执行插入操作...}
}

2.2 锁的获取条件

  1. 桶不为空时才会加锁
  2. 只锁住当前桶的头节点
  3. 通过 synchronized 关键字实现(JVM优化后的偏向锁/轻量级锁)

3. 实现步骤分解

3.1 插入元素时的锁控制流程

  1. 计算 key 的哈希并定位桶位置
  2. 如果桶为空,使用 CAS 无锁插入
    if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null)))break;
    
  3. 如果桶不为空,则锁住头节点:
    synchronized (f) {// 处理链表或树
    }
    

3.2 锁的细粒度验证

synchronized (f) {if (tabAt(tab, i) == f) { // 再次确认当前节点仍是头节点// 实际处理逻辑}
}

这种双重检查确保:

  • 防止在获取锁期间桶已被其他线程修改
  • 保证操作的原子性

4. 技术优势

  1. 更高的并发度

    • 理论上并发度 = 哈希桶数量(默认16 → 可能成千上万)
  2. 更低的锁竞争

    • 不同桶的操作完全并行
    • 只有哈希冲突时才会竞争
  3. 自适应锁优化

    • JVM 会根据竞争情况自动升级锁(偏向锁→轻量级锁→重量级锁)
  4. 与扩容协同

    • 扩容时通过 ForwardingNode 保证操作可以继续

5. 与 Java 7 分段锁对比

特性Java 7 分段锁Java 8 桶级别锁
锁粒度段(默认16)单个桶
锁实现ReentrantLocksynchronized
读操作需要段锁完全无锁
扩容段独立扩容整体协同扩容
冲突处理链表链表+红黑树

6. 实际代码示例

6.1 链表情况下的锁应用

// putVal方法片段
synchronized (f) {if (tabAt(tab, i) == f) {if (fh >= 0) { // 普通链表节点binCount = 1;for (Node<K,V> e = f;; ++binCount) {// 遍历链表...if ((e = e.next) == null) {e.next = new Node<K,V>(hash, key, value, null);break;}}}}
}

6.2 树情况下的锁应用

else if (f instanceof TreeBin) {Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) {oldVal = p.val;if (!onlyIfAbsent)p.val = value;}
}

7. 关键设计考量

  1. synchronized 优化

    • Java 6 后 synchronized 性能已大幅提升
    • JVM 会根据竞争情况自动优化
  2. CAS 失败回退

    • 当 CAS 插入失败(竞争)时才使用锁
  3. 死锁避免

    • 只按固定顺序获取单个锁
    • 不会出现交叉锁请求
  4. 内存可见性

    • 通过 volatile 变量保证
    • setTabAt/tabAt 使用 Unsafe 保证原子性

这种桶级别锁设计使得 ConcurrentHashMap 在 Java 8 中实现了:

  • 更高的并发吞吐量
  • 更低的操作延迟
  • 更平滑的性能曲线
  • 更好的可扩展性
http://www.xdnf.cn/news/15336.html

相关文章:

  • css如何同时给元素设置背景和背景图?
  • 004_Claude功能特性与API使用
  • 垃圾收集器-Serial Old
  • Java_Springboot技术框架讲解部分(二)
  • 飞算JavaAI:开启 Java 开发 “人机协作” 新纪元
  • PyTorch武侠演义 第一卷:初入江湖 第3章:神经网络派的绝世武功
  • 全星质量管理QMS软件系统——汽车零部件制造业数字化转型的质量管理中枢
  • Mybatis 两级缓存可能导致的问题
  • 如何成为 PostgreSQL 中级专家
  • 算法学习笔记:18.拉斯维加斯算法 ——从原理到实战,涵盖 LeetCode 与考研 408 例题
  • IT岗位任职资格体系及发展通道-产品经理岗位任职标准参考
  • 力扣经典算法篇-19-判断子序列(双指针法,双指针递归法,批量校验时的进阶解法(预处理+二分查找))
  • AI交互中的礼貌用语:“谢谢“的效用与代价分析
  • Sping AI Alibaba
  • 【unitrix】 5.1 第二套类型级二进制数基本结构体(types2.rs)
  • Sqlmap工具下载及使用
  • 【算法】贪心算法入门
  • 算法学习笔记:19.牛顿迭代法——从原理到实战,涵盖 LeetCode 与考研 408 例题
  • 【SCI 4区推荐】《Journal of Visual Communication and Image Representation》
  • 代码随想录|图论|14有向图的完全可达性
  • 集训Demo1
  • CVPR2025 Mamba系列
  • JAVA--双亲委派机制
  • 维基艺术图片: python + scrapy 爬取图片
  • Linux系统中部署Redis详解
  • 算法练习6-大数乘法(高精度乘法)
  • RocketMQ-
  • 【字符串移位包含问题】2022-8-7
  • Opencv---深度学习开发
  • 单细胞入门(1)——介绍