问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

ConcurrentHashMap 在Jdk 17 不同版本中的优化和改进

创作时间:
作者:
@小白创作中心

ConcurrentHashMap 在Jdk 17 不同版本中的优化和改进

引用
CSDN
1.
https://blog.csdn.net/bingyuea/article/details/145716752

ConcurrentHashMap 是 Java 中的一个高性能线程安全的哈希表实现,随着 JDK 版本的迭代,其内部实现也经历了多次优化和改进。每个版本的改动针对不同的场景和需求进行了性能提升和问题修复。以下分别描述了 JDK 7、JDK 8 和 JDK 17 的主要设计和区别,并探讨了 JDK 17 的优化。

JDK 7 中的 ConcurrentHashMap

在 JDK 7 中,ConcurrentHashMap 使用的是分段锁(Segment-based locking)的设计。这种设计是通过将整个哈希表分成若干段(Segment),每段锁住部分桶来允许更高的并发度。

  • 设计特点

  • 哈希表被划分为多个 Segment,每个 Segment 都是一个独立的小型哈希表。

  • 针对每个 Segment 使用一个独立的锁,也就是说,一个线程修改某个 Segment 的数据不会影响其他线程对其他 Segment 的访问。

  • 每次触发写操作时,只需要对相应 Segment 加锁,而不是全表加锁。

  • 优缺点

  • 在高并发下性能表现较好,读操作无需锁定,只锁定写操作。

  • 并发粒度取决于 Segment 的数量(默认是 16),并发度有限。

  • 容量扩展时,每个 Segment 独立扩容,操作较复杂。

JDK 8 中的 ConcurrentHashMap

JDK 8 对 ConcurrentHashMap 的实现进行了大幅改进,采用了更加细粒度的锁和无锁化设计,摒弃了 JDK 7 中的分段锁结构,转而引入基于 CAS(Compare-And-Swap)的操作和红黑树优化。

  • 设计特点

  • 引入了 Node 数组结构,直接取代了 Segments,并采用了与 HashMap 类似的方式存储键值对。

  • CAS 操作:通过 Unsafe 类的 CAS 指令操作底层数据,避免了锁的使用。

  • 红黑树优化:当链表长度超过一定阈值(默认 8)时,将链表转换为红黑树,以避免链表过长时导致的查询性能下降。

  • 扩容时使用分批迁移机制(Rehashing),由多个线程共同完成,降低扩容引起的性能问题。

  • 对 compute() 和 computeIfAbsent() 等操作进行了额外的同步控制,以支持复杂操作的线程安全性。

  • 改进效果

  • 移除了分段锁的限制,并发性提高。

  • 在链表出现太长时性能瓶颈显著降低。

JDK 17 中的 ConcurrentHashMap 的优化和改进

随着 JDK 的演进,ConcurrentHashMap 在 JDK 17 中进一步完善了设计,修复了一些潜在问题,同时在结构和算法上进行了优化,提升了并发性能和稳定性。

性能优化

  • 更好的 CAS 重试逻辑
  • CAS 失败时的回退算法(退避机制)在 JDK 17 中进一步优化,以减少自旋导致的 CPU 消耗。
  • 对热点桶(比如在高并发下频繁访问的区域)进行了优化,使冲突降低。
  • 减少内存屏障的开销
  • 在兼容 JMM(Java 内存模型)的约束下,减少了不必要的内存屏障,改善了具体操作中的指令开销。
  • 改进批量操作的并发性能
  • 提升了 forEach, search, reduce 等聚合操作的并行度和效率,尤其是在高并发场景下对大数据集的处理能力。

锁冲突优化

  • 在高并发场景中,当多个线程试图访问同一个节点时,JDK 17 中对节点锁的分配和抢占做了额外优化。例如,通过更智能的锁竞争算法来减少线程切换带来的上下文切换成本。

红黑树相关修复

  • 修复了一些早期版本中红黑树实现的边缘问题(例如某些极端情况下可能导致的死循环问题)。
  • 优化了树结构在并发扩容和修改时的效率。

线程挂起与唤醒机制改进

  • 在高并发写操作下,当线程需要等待其他线程完成某个关键部分(如扩容操作)时,采用了更加轻量化的线程挂起与唤醒机制,减少了不必要的上下文切换和线程阻塞。

代码质量和一致性

  • 官方对代码进行了持续重构与优化,重点解决一些此前版本的边界条件、竞争状态(race condition)等潜在问题。
  • 保持与其他并发集合类(例如 ConcurrentSkipListMap)的操作逻辑风格一致。

JDK 7、8 和 17 中 ConcurrentHashMap 的主要差异总结

特性
JDK 7
JDK 8
JDK 17
锁机制
使用分段锁(Segment)
基于 CAS 和 synchronized 锁
改进的 CAS,减少锁竞争
数据结构
Segment+ 链表
Node+ 链表 + 红黑树
更优化的 Node+ 链表 + 红黑树
扩容机制
每个 Segment 独立扩容
分批迁移完成扩容
改进的扩容效率,线程间协作更高效
高并发性能
易受分段数量限制
支持更高并发
性能进一步优化,高并发吞吐率提升
复杂操作支持(如计算)
较为有限
支持 compute 等复杂操作
改进 compute 等方法的性能

总结

  1. JDK 7 采用的是分段锁模型,适合中等并发的场景。
  2. JDK 8 引入了 CAS 和红黑树机制,极大提升了高并发场景下的性能,并摒弃了分段锁设计,成为近代 JVM 中并发集合的基础。
  3. JDK 17 在 JDK 8 的基础上进一步提升了并发性能,对锁冲突、CAS 回退、扩容机制等进行了优化,并修复了红黑树实现中的一些边缘问题,适用于更高并发的场景。

通常情况下,使用 JDK 17 提供的 ConcurrentHashMap 即可获得最好的性能和健壮性。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号