ConcurrentHashMap源码解读

2023-11-20

曾经研究过jkd1.5新特性,其中ConcurrentHashMap就是其中之一,其特点:效率比Hashtable高,并发性比hashmap好。结合了两者的特点。
   集合是编程中最常用的数据结构。而谈到并发,几乎总是离不开集合这类高级数据结构的支持。比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap)。这篇文章主要分析jdk1.5的3种并发集合类型(concurrent,copyonright,queue)中的ConcurrentHashMap,让我们从原理上细致的了解它们,能够让我们在深度项目开发中获益非浅。

    在tiger之前,我们使用得最多的数据结构之一就是HashMap和Hashtable。大家都知道, HashMap中未进行同步考虑,而Hashtable则使用了synchronized,带来的直接影响就是可选择,我们可以在单线程时使用HashMap提高效率,而多线程时用Hashtable来保证安全。
    当我们享受着jdk带来的便利时同样承受它带来的不幸恶果。通过分析Hashtable就知道, synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,安全的背后是巨大的浪费,慧眼独具的DougLee立马拿出了解决方案----ConcurrentHashMap。
 
    ConcurrentHashMap和Hashtable主要区别就是围绕着锁的粒度以及如何锁。如图


左边便是Hashtable的实现方式---锁整个hash表;而右边则是ConcurrentHashMap的实现方式---锁桶(或段)。 ConcurrentHashMap将hash表分为16个桶(默认值),诸如get,put,remove等常用操作只锁当前需要用到的桶。试想,原来 只能一个线程进入,现在却能同时16个写线程进入(写线程才需要锁定,而读线程几乎不受限制,之后会提到),并发性的提升是显而易见的。

    更令人惊讶的是ConcurrentHashMap的读取并发,因为在读取的大多数时候都没有用到锁定,所以读取操作几乎是完全的并发操作,而写操作锁定的粒度又非常细,比起之前又更加快速(这一点在桶更多时表现得更明显些)。 只有在求size等操作时才需要锁定整个表。而在迭代时, ConcurrentHashMap使用了不同于传统集合的快速失败迭代器(见之前的文章《JAVA API备忘---集合》)的另一种迭代方式,我们称为弱一致迭代器。在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出 ConcurrentModificationException,取而代之的是在改变时new新的数据从而不影响原有的数 据,iterator完成后再将头指针替换为新的数据,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变,更重要的,这保证 了多个线程并发执行的连续性和扩展性,是性能提升的关键。
    接下来,让我们看看ConcurrentHashMap中的几个重要方法,心里知道了实现机制后,使用起来就更加有底气。
    ConcurrentHashMap中主要实体类就是三个: ConcurrentHashMap(整个Hash表),Segment(桶),HashEntry(节点),对应上面的图可以看出之间的关系。
    get 方法(请注意,这里分析的方法都是针对桶的,因为ConcurrentHashMap的最大改进就是将粒度细化到了桶上),首先判断了当前桶的数据个数是 否为0,为0自然不可能get到什么,只有返回null,这样做避免了不必要的搜索,也用最小的代价避免出错。然后得到头节点(方法将在下面涉及)之后就 是根据hash和key逐个判断是否是指定的值,如果是并且值非空就说明找到了,直接返回;程序非常简单,但有一个令人困惑的地方,这句 return readValueUnderLock(e)到底是用来干什么的呢?研究它的代码,在锁定之后返回一个值。但这里已经有一句V v = e.value得到了节点的值,这句return readValueUnderLock(e)是否多此一举?事实上,这里完全是 为了并发考虑的,这里当v为空时,可能是一个线程正在改变节点,而之前的 get操作都未进行锁定,根据bernstein条件,读后写或写后读都会引起数据的不一致,所以这里要对这个e重新上锁再读一遍,以保证得到的是正确值,这里不得不佩服Doug Lee思维的严密性。整个get操作只有很少的情况会锁定,相对于之前的Hashtable,并发是不可避免的啊!
总结:
1、concurrenthashMap结合了hashtable与hashmap的优点,实现分段锁,使用的锁是ReentrantLock(重入锁)
2、concurrentHashMap 读操作不进行加锁
3、 concurrentHashMap 扩容时不对整个容器扩容,只对segment进行扩容
4、统计map长度时会对整个map的增删改操作进行加锁,所以此时性能会比较低。建议在循环时先拿到长度,不会每次都去重新拿一下
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ConcurrentHashMap源码解读 的相关文章

  • Java OS X Lion 关于菜单

    我正在尝试覆盖 OS X Lion 上的 Java 应用程序或 Leopard 及以上版本中的任何内容中的 关于 菜单 我怎么做 到目前为止 我读过的教程似乎不是最新的 一些类不再在 Java Mac SDK 中 其他类的事件也没有被触发
  • Spring 配置:无法找到 Spring NamespaceHandler

    配置问题 无法找到 XML 模式名称空间的 Spring NamespaceHandler http www springframework org schema tx http www springframework org schema
  • 如何在 Spring MVC 中使用延迟加载

    Spring MVC中如何使用延迟加载 我现在正在使用 eager 但这会使我的应用程序运行速度变慢 这是我的域的一部分 ManyToMany fetch FetchType EAGER JoinTable name NEWS TAG jo
  • IBM WebSphere MQ 2042 错误

    我有以下代码 int openOptions MQC MQOO INQUIRE MQC MQOO FAIL IF QUIESCING MQC MQOO INPUT SHARED 执行时 我收到错误 com ibm mq MQExceptio
  • 如何重构“字符串类型”代码?

    我目前正在开发一个代码库 其中有几类变量 例如数据库路径 它们简单地表示为字符串 这些 非 类型的大多数操作都在实用程序类中定义 我创建了一个新类来表示数据库 并将操作定义为实例方法 采用传统的 OOP 风格 然而 浏览大型代码库并重构它以
  • Apache Poi 无法读取工作表名称

    我们在通过 Apache Poi 读取 Excel 工作表时遇到了一个奇怪的错误 我们使用的是5 0版本 该代码以前可以工作 但现在已停止在我们所有的生产环境中工作 它在本地测试时仍然有效 因此事实证明这很难调试 问题是我们返回了空工作表名
  • 为什么图很大时x轴消失了

    我正在尝试使用加载大图JFreeChart 但是 当缓冲图像超过一定大小时 X 轴会出现问题 这些值在 X 轴上消失 这可以在图像的第三张图中看到 I would appreciate any help in fixing the prob
  • 根据使用频率随机生成字母?

    如何根据常用语音中的使用频率随机生成字母 任何伪代码都值得赞赏 但如果用 Java 实现就更棒了 否则 只需朝正确的方向戳一下就会有所帮助 注意 我不需要生成使用频率 我确信我可以很容易地查找到它 我假设您将频率存储为 0 到 1 之间的浮
  • 有没有一种简单的方法来加密java对象?

    我想将序列化对象存储到文件中 但我想对其进行加密 它不需要非常强的加密 我只是想要一些简单的东西 最好是最多几行代码 这会让其他人加载起来更加困难 我已经研究过 SealedObject 但关键是阻止我 理想情况下 我只想传递一个字符串作为
  • 如何对包含字符串数组的数组列表进行排序?

    List
  • Java HTTPS客户端证书认证

    我对HTTPS SSL TLS我对客户在使用证书进行身份验证时到底应该提供什么内容感到有点困惑 我正在编写一个 Java 客户端 需要执行一个简单的操作POST数据到特定的URL 这部分工作正常 唯一的问题是它应该重新完成HTTPS The
  • Clojure/Java:用于声音频谱分析的 Java 库? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个可以接受大量音频数据并返回给定频带内随时间变化的平均幅度的库 我已经在 comp dsp
  • 在具有重载构造函数的类中传递 null 时,首先调用哪个构造函数?

    下面是具有 3 个重载构造函数的 java 类 public class Test public Test Object i System out println Object invoked public Test String i Sy
  • Java 泛型和数字

    为了看看我是否可以清理一些数学代码 主要是矩阵代码 我尝试使用一些 Java 泛型 我有以下方法 private
  • 如何停止在控制台上打印异常堆栈跟踪?

    我编写了一个 Servlet 来处理 Web 应用程序中发生的异常 并将它们映射到 web xml 中
  • java中调用父构造函数

    我有两节课Parent and Child 而Parent有一个需要 3 个参数的构造函数 class Parent public Parent String host String path int port 现在我想要Child构造函数
  • 通过JVMTI识别异常

    我正在使用 JVMTI 为 Java 应用程序编写一个检测工具 我已经看到 JVMTI 检测何时抛出异常以及何时捕获异常http docs oracle com javase 7 docs platform jvmti jvmti html
  • 添加 2 个 BigDecimal 值 [重复]

    这个问题在这里已经有答案了 class Point BigDecimal x BigDecimal y Point double px double py x new BigDecimal px y new BigDecimal py vo
  • 如何从 netbeans 远程调试 jar

    我正在尝试弄清楚如何调试远程运行的 jar 这是我的场景 我的 jar 将从 VPS 运行 这个jar基本上运行一个服务器 对于游戏 所以它还连接到 mysql 数据库 我使用 3 个 bat 文件启动服务器 如下所示 设置 CLASSPA
  • 为什么不建议将常量存储在单独的类中?

    有人告诉我 我在其他一些地方也看到过这种说法 不建议将常量存储在 Java 中的单独类中 以便在其他类中使用它们 但我没有看到任何地方为什么会这样 我不应该将它们存储在自己的接口 类中的原因是什么 我从 C 转到 Java 在 C 中我只想

随机推荐

  • FreeRTOS多任务调度器基础

    Cortex M4中SysTick调度器核心 Cortex M4中的中断管理 Cortex M4中影子栈指针 Cortex M4中SVC和PendSV异常 1 Cortex M4中SysTick调度器核心 systick每一次中断都会触发内
  • c语言—指针非常全面、详细

    目录 一 初步认识指针 一级 二 数组指针 1 一维数组与指针 2 二维数组与指针 三 函数指针 四 指针数组 2 函数指针数组 五 指针函数 六 二级 多级 指针 七 指针定义的归纳 一 初步认识指针 一级 1 指针变量 指针变量是一个特
  • c++优先队列简介及例题:5.4.1 围栏修复

    优先队列 其实就是个队列 只不过里面的元素会被自动按一定的顺序来排列 可以是递增顺序 也可以是递减顺序 写法如下 头文件 include
  • 020 - STM32学习笔记 - Fatfs文件系统(二) - 移植与测试

    020 STM32学习笔记 Fatfs文件系统 二 移植与测试 上节学习了FatFs文件系统的相关知识 这节内容继续学习在STM32上如何移植FatFs文件系统 并且实现文件的创建 读 写与删除等功能 各位看官觉得还行的话点点赞 收藏一下呗
  • FastDFS-01-单机和集群搭建

    我是码赛客1024 本节我们一起搭建FastDFS 一 介绍 FastDFS是一个开源的轻量级分布式文件系统 它对文件进行管理 功能包括 文件存储 文件同步 文件访问 文件上传 文件下载 等 解决了大容量存储和负载均衡的问题 特别适合以文件
  • 对象创建的几个步骤

    对象创建的几个步骤 一 先把要创建的对象的类信息加载进内存 二 在内存开辟空间 1 如果内存是规整的 则使用指针碰撞 2 如果不规整 则会维护一个空闲列表 内存是否规整根据具体的垃圾回收算法来决定 三 开辟空间需要解决并发问题 在堆中创建对
  • shell脚本一键安装JDK及配置环境变量

    这是我学了半天shell写出来的 不适合大神看 为什么我要写这样安装JDK并配置环境变量的脚本呢 因为我和linux打交道还是比较多的 然而每次都要安装JDK 配置环境变量 这样的事情对于刚接触linux的人来说是很乐意做的 但是接触多了
  • 浏览器请求队列机制-请求为什么会阻塞

    前言 最近遇到一个问题 我1个站点链接2个后端服务 但1个后端服务有问题 导致访问超时 但请求接口都是分开的 自认为一个服务站点请求超时 不会影响到另外一个请求的 但不是 全部请求都发不出去 为什么呢 是不是浏览器有请求机制管理 正常情况前
  • html理解MVC模型与MVVM模型底层实现

    一 MVC模型的底层实现 1 1 相关代码 div div
  • python基础编程小实例13——手机通讯录

    本文更新于2022 05 18 bug已修复 编程语言 python3 9 题目 可以在通讯录中通过姓名查看相关联系人的联系方式等信息 也可以在其中新增联系人 或修改 删除联系人信息 本实例要求编写程序 实现具备添加 查看 修改以及删除联系
  • react 上传文件(多选)功能入的坑

    1 这里报错是因为onChange的this指向不对 解决方法在constructor中写 this onChange this onChange bind this 或者在绑定事件的时候写 onChange this onChange b
  • Unity Animator 动画没切换

    恶魔射手 Survival Shooter 项目 有两个动画 一个是静止时的Idle 一个是走路时候的Move 如下图 设置好动画状态机后发现按方向键后还是Idle 没反应 而一直按着方向键后呢又动起来了 最后找到了真相 原来选中了 Has
  • 使用yolov7模型用VOC深度学习

    yolov7及VOC数据集 权重文件地址 bubbliiiing yolov7 pytorch 这是一个yolov7的库 可以用于训练自己的数据集 github com 在colab中 训练 1 voc annotation py 如果使用
  • Python 判断数组list是否为空

    前言 判断数组为空 是一个常见用法 Python与Java的方法不同 需区分 Python 方法 1 根据长度判断 长度为0时 表示空 其中 判断条件 成立时 非零 则执行后面的语句 lst if len lst print c else
  • 如何在mybatis 中传多个参数,如何在mybatis 中遍历 集合?

    如何在mybatis 中传多个参数 List getIdByRand Param question Question question Param sectionIdList List sectionIdList param 映射参数到 x
  • .NET的RulesEngine(规则引擎)使用

    本文目录 1 背景说明 1 1 规则引擎的使用场景 1 2 demo的代码说明 2 演示 2 1 入门demo演示 2 1 1 代码展示 2 1 2 代码下载 2 2 规则参数说明 2 2 1 第一部分参数说明 2 2 2 第二部分参数说明
  • 2021.9.5笔试题

    第一题 题目 找x y target 数字特别大 可能会溢出 代码 include
  • CPU 100%问题排查

    1 top c top c 命令找出当前进程的运行列表 按一下 P 可以按照CPU使用率进行排序 显示Java进程 PID 为 2609 的java进程消耗最高 2 top Hp pid 然后我们需要根据PID 查出CPU里面消耗最高的进程
  • sklearn的make_circles和make_moons生成数据

    关于make circles and make moons生成环形形状和月亮形状数据 转载来源 https blog csdn net dataningwei article details 53649330 make circles sk
  • ConcurrentHashMap源码解读

    曾经研究过jkd1 5新特性 其中ConcurrentHashMap就是其中之一 其特点 效率比Hashtable高 并发性比hashmap好 结合了两者的特点 集合是编程中最常用的数据结构 而谈到并发 几乎总是离不开集合这类高级数据结构的