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

在 JDK 1.8 的 ConcurrentHashMap 中,为什么存在两种插入方式?

在 JDK 1.8 的 ConcurrentHashMap 中,之所以对“容器为空”和“计算位置为空”采取不同的处理方式,主要是因为 并发场景下的性能优化和并发安全保证。我们可以分开来看这两种情况:

1. 容器为空时,使用 volatile + CAS 初始化

  • 原因ConcurrentHashMap 采用 懒加载,并不会在构造时就初始化所有桶(Node<K, V>[] table)。

  • 实现:当第一次插入元素时,会先判断 table 是否为空:

if (tab == null || (n = tab.length) == 0) 
    tab = initTable();
  • initTable() 方法使用 CAS(Compare-And-Swap) 操作来保证线程安全的初始化。

  • 为什么用 CAS 而不是 synchronized?

    • 目的是减少不必要的锁竞争,提高并发性能。
    • 由于初始化操作通常只需要执行一次(典型的 双重检查锁 模式),CAS 在多数情况下不会失败,所以开销较小。

2. 计算出的位置为空时,使用 CAS 插入

  • 原因:如果某个桶(即 table[index])位置为空,说明没有哈希冲突,我们可以直接尝试插入数据。
  • 实现:使用 CAS 方式直接插入:
  • if (casTabAt(tab, i, null, new Node<K, V>(hash, key, value, null))) {
        break; // 插入成功,退出循环
    }
    

    为什么用 CAS 而不是 synchronized?

  • 因为这个位置是 null,没有竞争,所以可以直接尝试用 无锁的 CAS 操作 插入,避免加锁的开销,提高性能。

3. 计算出的位置不为空时,使用 synchronized

  • 原因:如果 table[index] 位置已经有元素了,可能会遇到 哈希冲突,需要遍历该链表或红黑树进行替换或追加。

  • 实现

    • 先通过 synchronized 锁住该桶(synchronized (f))。
    • 然后遍历这个桶:
      • 如果 key 已存在,则更新 value。
      • 如果 key 不存在,则添加新的节点(链表 or 红黑树)。
    • 插入完成后,判断链表长度是否达到阈值(8),如果达到就转换为红黑树
  • 为什么用 synchronized 而不是 CAS?

    • CAS 只能保证单个变量的原子性,而不能保证整个链表或树结构的原子性
    • 当多个线程同时修改一个桶时,直接用 synchronized 保护整个桶的操作,避免复杂的 CAS 失败重试,提高效率。

JDK 1.8 在 ConcurrentHashMap 中通过 分阶段使用 CAS 和 synchronized,既保证了 高并发性能,又保证了 线程安全,这就是它不同情况下采用不同方式的原因。

http://www.dtcms.com/a/63046.html

相关文章:

  • 解决vscode中出现“无法将pip项识别...“问题
  • 2025软件供应链安全案例︱证券行业云原生DevSecOps敏捷安全实践
  • 实施一套先进的智能摄像头服务系统。
  • HMT-UNet模型详解及代码复现
  • BERT、T5、GPTs,Llama
  • 2025年直播商城系统源码发展趋势:电商带货APP的技术革新
  • Java平衡二叉树
  • 具备多种功能的PDF文件处理工具
  • spring的data派生查询机制详解
  • LLM剪枝代码解释与实现
  • 计算机网络-应用层
  • 几种常见的虚拟环境工具(Virtualenv、Conda、System Interpreter、Pipenv、Poetry)的区别和特点总结
  • 基于redisson实现接口幂等性
  • 自然语言处理:主题模型
  • 05.基于 TCP 的远程计算器:从协议设计到高并发实现
  • 类和对象(下)
  • 器官层面的实例分割能够实现对临床前腹部光声断层扫描图像的连续时空光谱分析|文献速递-医学影像人工智能进展
  • 【HDLbits--分支预测器简单实现】
  • DeepLabv3+改进8:在主干网络中添加SIM注意力机制|助力涨点
  • Xenium最新文章 | 空间转录组揭示食管癌多阶段空间演化图谱
  • ChatGPT4.5详细介绍和API调用详细教程
  • 要在Unreal Engine 5(UE5)中实现角色打击怪物并让怪物做出受击反应,
  • 数据库---sqlite3
  • C#控制台应用程序学习——3.11
  • Spring Cloud之远程调用OpenFeign
  • 【Linux】信号
  • 图片查看器:用PyQt5实现本地图片预览工具
  • 使用AOP + Prometheus + node-exporter + grafana 实现Java系统的接口监控
  • 【自动化】Automa网页自动化之路
  • ⭐算法OJ⭐链表排序【归并排序】(C++/JavaScript 实现)