JDK7 和 JDK8 的 ConcurrentHashMap

ConcurrentHashMap JDK1.7 JDK1.8详解 ConcurrentHashMap是并发工具包的集合不同于HashMap,HashMap它是一个线程不安全的集合而ConcurrentHashMap是一个线程安全的集合。 Hashtable跟HashMap在源代码的实现上是差不多一样的,但它是线程安全的因为HashTable的每一个方法都上锁了。HashTable锁了方法导致HashTable只有一把锁而这把锁就是HashTable的对象,所以HashTable的并发量低。 为了实现线程安全以及高并发的需求就有了ConcurrentHashMap,Co 阅读详情

一、Segment

JDK7 的 HashMap在高并发下会出现链表环,从而导致程序出现死循环。可以使用 HashTable、Collections.syncronizedMap 替代,但是二者性能都很差。因为在执行读写操作时都是将整个集合加锁,导致多个线程无法同时读写集合。因此,高并发下的 HashMap 出现的问题就需要 ConcurrentHashMap 来解决了。

【JDK7 的 ConcurrentHashMap】中有一个 Segment 的概念。Segment 本身就相当于一个 HashMap 对象。同 HashMap 一样,Segment 包含一个 HashEntry 数组,数组中的每一个 HashEntry 既是一个键值对,也是一个链表的头节点。单一的 Segment 结构如下:

ConcurrentHashMap 中有 2 的 n 次方个 Segment 对象,共同保存在一个名为 segments 的数组当中。因此整个 ConcurrentHashMap 的结构如下:

可以说,ConcurrentHashMap 是一个二级哈希表。在一个总的哈希表下面,有若干个子哈希表。这样的二级结构,和数据库的水平拆分有些相似。

1️⃣ConcurrentHashMap 的优势
采取了锁分段技术,每一个 segment 就好比一个自治区,读写操作高度自治,segment 之间互不影响。

Case1:不同 segment 的并发写入【可以并发执行】

Case2:同一 segment 的一写一读【可以并发执行】

Case3:同一 segment 的并发写入【需要上锁】

由此可见,ConcurrentHashMap 中每个 segment 各自持有一把锁。在保证线程安全的同时降低了锁的粒度,让并发操作效率更高。

2️⃣Concurrent 的读写过程

Get 方法:

  1. 为输入的 Key 做 Hash 运算,得到 hash 值。(为了实现 segment 均匀分布,进行了两次 Hash)
  2. 通过 hash 值,定位到对应的 segment 对象。
  3. 再次通过 hash 值,定位到 segment 当中数组的具体位置。

Put 方法:

  1. 为输入的 Key 做 Hash 运算,得到 hash 值。
  2. 通过 hash 值,定位到对应的 segment 对象。
  3. 获取可重入锁。
  4. 再次通过 hash 值,定位到 segment 当中数组的具体位置。
  5. 插入或覆盖 HashEntry 对象。
  6. 释放锁。

从步骤可以看出,ConcurrentHashMap 在读写时均需要二次定位。首先定位到 segment,之后定位到 segment 内的具体数组下标。

二、每个 segment 都各自加锁,在调用 size() 的时候,怎么解决一致性的问题

1️⃣调用 size() 是统计 ConcurrentHashMap 的总元素数量,需要把各个 segment 内部的元素数量汇总起来。但是,如果在统计 segment 元素数量的过程中,已统计过的 segment 瞬间插入新的元素,此时该如何?

2️⃣ConcurrentHashMap 的 size() 是一个嵌套循环,大体逻辑如下:

  1. 遍历所有的 segment。
  2. 把 segment 的元素数量累加起来。
  3. 把 segment 的修改次数累加起来。
  4. 判断所有 segment 的总修改次数是否大于上次的总修改次数。如果大于,说明统计过程中有修改,重新统计,尝试次数 +1;如果不是说明没有修改,统计结束。
  5. 如果尝试次数超过阈值,则对每一个 segment 加锁,再重新统计。
  6. 再次判断所有 segment 的总修改次数是否大于上次的总修改次数。由于已经加锁,次数一定和上次相等。
  7. 释放锁,统计结束。

官方源代码如下:

为什么这样设计呢?这种思想和乐观锁的思想如出一辙。为了尽量不锁住所有的 segment,首先乐观地假设 size 过程中不会有修改。当尝试一定次数,才转为悲观锁,锁住所有 segment 保证强一致性。

三、ConcurrentHashMap(线程安全)

  • 底层采用分段的数组+链表实现
  • 通过把整个 map 分为 n 个 segment,保证线程安全,效率提升 n 倍,默认提升 16 倍。(读操作不加锁,由于 HashEntry 的 value 变量是volatile的,也能保证读取到最新的值。)
  • Hashtable 的synchronized是针对整张 Hash 表的,即每次锁住整张表让线程独占,ConcurrentHashMap 允许多个修改操作并发进行,其关键在于使用了锁分离技术。
  • 有些方法需要跨段,比如 size() 和 containsValue(),它们可能需要锁定整个表而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。
  • 扩容:段内扩容(段内元素超过该段对应 HashEntry 数组长度的 75% 触发扩容,不会对整个 map 进行扩容),插入前检测是否需要扩容,避免无效扩容。

从类图可看出在存储结构中 ConcurrentHashMap 比 HashMap 多出了一个类 Segment,而 Segment 是一个可重入锁。ConcurrentHashMap 是使用了锁分段技术来保证线程安全的。

锁分段技术:
首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据仍能被其他线程访问。

ConcurrentHashMap 提供了与 Hashtable 和 SynchronizedMap 不同的锁机制。Hashtable 中采用的锁机制是一次锁住整个 hash 表,从而在同一时刻只能由一个线程对其进行操作;而 ConcurrentHashMap 中则是一次锁住一个桶。

ConcurrentHashMap 默认将 hash 表分为 16 个桶,诸如 get、put、remove 等常用操作只锁住当前需要用到的桶。这样,原来只能一个线程进入,现在同时能有 16 个写线程执行,并发性能的提升是显而易见的。

四、ConcurrentHashMap 的 JDK7/JDK8 区别

1️⃣整体结构

JDK7:Segment + HashEntry + Unsafe
JDK8:移除 Segment,使锁的粒度更小,Synchronized + CAS + Node + Unsafe

2️⃣put()

JDK7:先定位 Segment,再定位桶,put 全程加锁,没有获取锁的线程提前找桶的位置,并最多自旋 64 次获取锁,超过则挂起。
JDK8:由于移除了 Segment,类似 HashMap,可以直接定位到桶,拿到 first 节点后进行判断:①为空则 CAS 插入;②为 -1 则说明在扩容,则跟着一起扩容;③ else 则加锁 put(类似 JDK7)

3️⃣get()

基本类似,由于 value 声明为 volatile,保证了修改的可见性,因此不需要加锁。

4️⃣resize()

JDK7:跟 HashMap 步骤一样,只不过是搬到单线程中执行,避免了 HashMap 在 JDK7 中扩容时死循环的问题,保证线程安全。
JDK8:支持并发扩容,HashMap 扩容在 JDK8 中由头插改为尾插(为了避免死循环问题),ConcurrentHashmap 也是,迁移也是从尾部开始,扩容前在桶的头部放置一个 hash 值为 -1 的节点,这样别的线程访问时就能判断是否该桶已经被其他线程处理过了。

5️⃣size()

JDK7:很经典的思路:计算两次,如果不变则返回计算结果,若不一致,则锁住所有的 Segment 求和。
JDK8:用 baseCount 来存储当前的节点个数,这就涉及到 baseCount 并发环境下修改的问题。

五、问题

如何在很短的时间内将大量数据插入到 ConcurrentHashMap,换句话说,就是提高 ConcurrentHashMap 的插入效率。-----尽量散列均匀和避免加锁。

基于Simulink的固态变压器(SST)多级协同控制​ 本文介绍了基于Simulink的固态变压器(SST)多级协同控制方法。SST作为智能电网关键设备,其三级架构(AC-DC整流、DC-DC隔离、DC-AC逆变)存在级间耦合问题。文章提出纵向解耦与横向联动相结合的协同控制策略,详细推导了各级控制算法,并通过Simulink实现了10kV/400V级联型SST系统建模。仿真结果显示,在±20%电网波动和0-100%负载跳变下,系统能保持直流母线电压波动<2%。文章还提供了工程部署建议和代码生成方法,为SST的研发提供了实用指导。 阅读详情

相关推荐

DINOv3 网络结构解析:从 ViT 到 ConvNeXt 的双路线设计

本文深入解析了DINOv3网络结构的双路线设计,包括ViT和ConvNeXt两种主干架构。ViT路线通过轴向旋转位置编码解决了传统ViT对固定分辨率的依赖,而ConvNeXt路线则优化了卷积设计,提升了实时处理能力。文章还探讨了Gram Anchoring、混合自监督目标等关键技术,展示了DINOv3在多任务和多模态应用中的强大潜力。

weixin_29214199的博客 560

Java7 Java 8 HashMap ConcurrentHashMap源码解读

目录 Java7 HashMap Java7 ConcurrentHashMap Java8 HashMap Java8 ConcurrentHashMap 总结 原文:https://mp.weixin.qq.com/s/QggmWkrgYrNtVkdSKYuRfg Java7 HashMap HashMap不支持并发操作,源码简单。 数组+单向链表 绿色的实体是嵌套类 ...

weixin_38071106的博客 306

DEM边界数值爆炸?用ArcGIS空间分析工具链搞定异常值过滤全流程

本文针对DEM数据处理中常见的边界数值爆炸问题,提供了一套完整的ArcGIS空间分析解决方案。文章深入剖析了异常值产生的根源,并详细介绍了从诊断、定位到使用栅格计算器、重分类等工具进行精准过滤与修复的全流程工作流,帮助用户彻底解决由插值误差、数据拼接及坐标系转换引发的数值异常。

weixin_29269441的博客 147

简单了解 ConcurrentHashMap 在 JDK7 和 JDK8 中的区别

在了解 HashMap 的的原理时,对于 jdk7 和 8 的实现是不同的,同样,对于支持并发的 ConcurrentHashMap 来说其实现也不相同。 其主要区别在于两者保证线程安全的机制不同,jdk7 采用的是分段锁的概念,每一个分段都有一把锁,锁内存储的着数据,锁的个数在初始化之后不能扩容。 而 jdk8 的 ConcurrentHashMap 数据结构同 HashMap,通过 Synchronized+CAS 来保证其线程安全。 jdk7 在 jdk7 中,有一个非常重要的概念就是 Segment

个人站点:javatv.net 1433

手把手教你用Anaconda安装李沐d2l-zh包(附常见报错解决方案)

本文提供了一份详尽的Anaconda环境下安装李沐d2l-zh包的实战指南。文章从创建虚拟环境、配置国内镜像源加速下载入手,分步讲解核心依赖的预安装策略,并重点剖析了安装过程中常见的报错及其解决方法,旨在帮助初学者和开发者高效、稳定地搭建深度学习实验环境。

efc1234567的博客 1010

运算放大器电路仿真实践:从零实现完整示例

通过一个完整的运算放大器电路仿真示例,深入掌握电路仿真的关键步骤与技巧,帮助电子爱好者和工程师快速上手实际项目设计。

weixin_34725745的博客 1317

【Java面试】ConcurrentHashMap再JDK7和8中的区别以及ConcurrentHashMap底层实现

在多线程环境下,使用 HashMap 进行 put 操作时存在丢失数据的情况,为了避免这种bug的隐患,强烈建议使用 ConcurrentHashMap 代替 HashMap ,为了对更深入的了解,本文将对JDK1.7和1.8的不同实现进行分析。组的大小 cap ,并初始化 Segment 数组的第一个元素;2、如果相应位置的 Node 不为空,且当前该节点不处于移动状态,则对该节点加 synchronized 锁,如果该节点的 hash 不小于0,则遍历链表更新节点或插入新节点;

Zhangsama1的博客 1914

机械臂TCP标定实战:从四点法到六点法的精度跃迁

本文详细解析机械臂TCP标定技术,从基础的四点法到高精度的六点法实现精度跃迁。通过工具坐标系与基坐标系的转换原理,结合实战案例展示六点法如何将装配合格率提升至99.5%,并分享环境控制、操作技巧等提升标定精度的关键要素。

weixin_29038345的博客 893

深入揭秘 ConcurrentHashMap:JDK7 到 JDK8 并发优化的演进之路

从源码层次剖析 ConcurrentHashMap 的线程安全机制,比较 JDK7 分段锁与 JDK8 CAS+红黑树方案,揭示其扩容、树化与高并发优化的核心原理。

weixin_47762494的博客 3619

OpenClaw更新后变傻了?一分钟教你快速恢复(OpenClaw更新版本后降智、缺少权限问题的解决方案)

OpenClaw 版本更新后出现降智问题,AI不再执行具体任务。本文详细分析问题原因,提供最简便的解决方案✅

XiaoqiangClub的博客 3876

大模型量化方法总结

本文主要对大模型量化方法进行了总结,希望对学习大语言模型的同学们有所帮助。 文章目录 1. 前言 2. 模型精度 3. 量化方法 3.1 方法一 3.2 方法二 3.3 方法三

herosunly的博客 1万+

ConcurrentHashMap原理,jdk7和jdk8版本的区别

它在 JDK 7 和 JDK 8 中的实现原理有显著的区别,主要是为了提高并发性能和扩展性。锁的粒度从段级别缩小到桶级别(每个桶是一个链表或红黑树),进一步减少了锁竞争。当链表长度超过阈值(默认 8)时,链表会转换为红黑树,提高查找性能。数据结构更高效,链表和红黑树的结合提高了查找性能。获取段的锁,然后在段内的哈希表中插入或更新键值对。,锁的粒度从整个表缩小到段级别,减少了锁竞争。),每个段是一个独立的哈希表,拥有自己的锁。分段锁的粒度仍然较大,高并发场景下性能有限。:尽量减少锁的竞争,提高并发性能。

完全体 932

YOLOv11改进 | 模型知识蒸馏篇 | 利用模型蒸馏改进YOLOv11进行无损涨点 | 在线蒸馏 (附代码 + 完整文件 + 解析教程)

这篇文章给大家带来的最新改进是模型的蒸馏,利用教师模型指导学生模型从而进行模型的涨点,本文的内容不仅可以用于论文中,在目前的绝大多数的工作中模型蒸馏是一项非常重要的技术,所以大家可以仔细学习一下本文的内容,本文从YOLOv11的项目文件为例,进行详细的修改教程,文章内包括完整的修改教程,针对小白我出了视频修改教程,如果你还不会我提供了修改后的文件大家直接运行即可,所以说不用担心不会适用!模型蒸馏真正的无损涨点,蒸馏你只看这一篇文章就足够了,本文内容为在线蒸馏教程,之前的文章为离线蒸馏!

Snu77的博客 2667

ConcurrentHashMap底层实现原理((JDK1.7&1.8))

目录前言ConcurrentHashMap (JDK1.7的实现)初始化put操作get操作size操作ConcurrentHashMap (JDK1.8的实现)NodeTreeNodeTreeBinput操作get操作size操作总结与思考 前言 我们都知道HashMap在多线程情况下,在put的时候,插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是rehash,这个会重新将原...

CoderZS的博客 1万+

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

深入解析 ConcurrentHashMap:从 JDK 1.7 到 JDK 1.8

JDK 1.7:使用分段锁(Segment)和,每个 Segment 是一个独立的小哈希表,适合中等并发场景。JDK 1.8:采用 CAS 操作和锁定链表或红黑树的首节点,提供了更细粒度的锁,适合高并发场景。通过这些改进,JDK 1.8 版本的在性能和并发控制方面有了显著的提升。觉得有用的话可以,支持一下。如果愿意的话关注一下。会对你有更多的帮助。每天都会不定时更新哦 >人<。

lenyan~的博客 2128

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

并发编程:JDK7 和 JDK8 的 ConcurrentHashMap 锁实现方案

项目核心结构Node[] + 链表/红黑树加锁方式锁住 Segment(ReentrantLock)锁桶头(synchronized)+ CAS并发读无锁,volatile + final 保证无锁,volatile 保证并发写锁一个 Segment(最多16个并发)精确到桶 + CAS,自旋扩容扩容全表加锁迁移多线程协作迁移(transferIndex)红黑树优化❌ 无✅ 桶内链表长度超过 8 转红黑树内存占用多 Segment 和锁,略高。

怪味Coding 501

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

ConcurrentHashMap 加锁机制:JDK 1.7 与 JDK 1.8 对比

在 JDK 1.7 中,采用了分段锁(Segment)的设计。整个由多个 Segment 组成,每个 Segment 类似于一个独立的HashMap,并且每个 Segment 都拥有自己独立的锁。这种结构使得在并发操作时,不同 Segment 之间的操作可以并行执行,只有当多个线程同时访问同一个 Segment 时才会发生锁竞争,从而在一定程度上提高了并发性能。在 JDK 1.7 和 JDK 1.8 中通过不同的加锁机制和数据结构设计,实现了高效的并发访问性能。

weixin_69477306的博客 1193

ConcurrentHashMap在jdk1.7和jdk1.8中的不同;

原博客: https://www.cnblogs.com/lujiango/p/7580558.html http://www.importnew.com/28263.html CouncurrentHashMap 线程安全 一、CouncurrentHashMap<jdk1.7> 1、底层: (1)底层数据结构: <jdk1.7>:数组(Segment) + 数组(H...

qq_41884976的博客 4万+

指定jdk8_ConcurrentHashMap的JDK7与JDK8对比学习

ConcurrentHashMap是面试的重点,尤其是jdk7与8的对比,这里进行总结对比学习。总结对比图直接上jdk7与jdk8对ConcurrentHashMap底层实现的对比图,对比如下图:jdk7的ConcurrentHashMap底层结构是Segment数组,可以在初始化的时候指定Segment数组的长度,并且不可变。而Segment继承了ReentrantLock,它存储数据的实现与H...

weixin_29783347的博客 120

ConcurrentHashMap在JDK 7和8之间的区别

ConcurrentHashMap原理,以及在jdk7和jdk8版本的区别

Master_Shifu_的博客 405

jdk1.7及1.8 hashMap,concurrentHashMap超详细源码剖析(附带自己理解注释)

java集合 jdk 1.7 HashMap 内部属性 public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { // 模拟初始容量,必须是2的幂 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 //最大容量

small_kai的博客 1064

ConcurrentHashMap原理,以及在jdk7和jdk8版本的区别

ConcurrentHashMap原理,以及在jdk7和jdk8版本的区别

aijson_update的博客 371

请分析ConcurrentHashMap在JDK 7和JDK 8中的实现差异,为什么JDK 8要放弃分段锁而采用CAS+synchronized的方案?这种变化带来了哪些性能影响?

是 Java 并发包中用于解决哈希表线程安全问题的核心类,JDK 7 和 JDK 8 中其底层实现有根本性差异,主要体现在锁机制、数据结构和扩容策略上。在大多数场景下性能更优,尤其适合高并发、大数据量的业务场景。优化和 CAS 操作弥补了分段锁的缺陷。JDK 8 放弃分段锁的核心原因是。和 synchronized。JDK 8 彻底重构了。,摒弃了分段锁,采用与。JDK 8 放弃分段锁(

weixin_43521001的博客 951

ConcurrentHashMap进化论:从JDK7的“分段锁“到JDK8的“CAS+synchronized

减少竞争:锁粒度从段→桶无锁优先:CAS替代部分锁操作动态适应:链表与树的互相转换协作精神:多线程共同参与扩容JDK7像固定车道的老式收费站JDK8则是智能调度的现代交通系统现在,是时候升级到JDK8+,享受更高效的并发性能了!

全栈开发工程师 1753

JDK 7 ConcurrentHashMap和JDK 8 ConcurrentHashMap

JDK7关于初始化ConcurrentHashMap满老师可能是口误,稍微有点问题,应该是默认的初始化先初始化16个分段锁(segments[16])并且仅在下标为0的位置(segments[0])初始化Segment对象(它有个重要的属性HashEntry数组,初始大小是2)...

m0_45364328的博客 197

ConcurrentHashMap原理,jdk7和jdk8版本的区别

ConcurrentHashMap原理,jdk7和jdk8版本的区别 jdk7: 数据结构: ReentrantLock+Segment+HashEntry,一个Segment中包含一个类似于HashMap的结构,数组+链表 元素查询:二次hash,第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部 锁: Segment分段锁Segment继承了ReentrantLock,锁定操作的Segment,其他的Segment不受影响,并发度为segment个数,可以通过构

abaidaye的博客 689
上一篇: JDK7 和 JDK8 的 HashMap
下一篇: Java中ArrayList和LinkedList区别
JFS_Study
博客等级 码龄6年 363粉丝 359原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JFS_Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值