Hashtable与ConcurrentHashMap区别

article/2025/8/22 7:22:59

ConcurrentHashMap融合了hashtable和hashmap二者的优势。

hashtable是做了同步的,hashmap未考虑同步。所以hashmap在单线程情况下效率较高。hashtable在的多线程情况下,同步操作能保证程序执行的正确性。

但是hashtable每次同步执行的时候都要锁住整个结构。看下图:

图左侧清晰的标注出来,lock每次都要锁住整个结构。

ConcurrentHashMap正是为了解决这个问题而诞生的。

ConcurrentHashMap锁的方式是稍微细粒度的。 ConcurrentHashMap将hash表分为16个桶(默认值),诸如get,put,remove等常用操作只锁当前需要用到的桶。

试想,原来 只能一个线程进入,现在却能同时16个写线程进入(写线程才需要锁定,而读线程几乎不受限制,之后会提到),并发性的提升是显而易见的。

更令人惊讶的是ConcurrentHashMap的读取并发,因为在读取的大多数时候都没有用到锁定,所以读取操作几乎是完全的并发操作,而写操作锁定的粒度又非常细,比起之前又更加快速(这一点在桶更多时表现得更明显些)。只有在求size等操作时才需要锁定整个表。

而在迭代时,ConcurrentHashMap使用了不同于传统集合的快速失败迭代器的另一种迭代方式,我们称为弱一致迭代器。在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出 ConcurrentModificationException,取而代之的是在改变时new新的数据从而不影响原有的数 据,iterator完成后再将头指针替换为新的数据,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变,更重要的,这保证了多个线程并发执行的连续性和扩展性,是性能提升的关键。

下面分析ConcurrentHashMap的源码。主要是分析其中的Segment。因为操作基本上都是在Segment上的。先看Segment内部数据的定义。

 

从上图可以看出,很重要的一个是table变量。是一个HashEntry的数组。Segment就是把数据存放在这个数组中的。除了这个量,还有诸如loadfactor、modcount等变量。

看segment的get 函数的实现:

加上hashentry的代码:

可以看出,hashentry是一个链表型的数据结构。

在segment的get函数中,通过getFirst函数得到第一个值,然后就是通过这个值的next,一路找到想要的那个对象。如果不空,则返回。如果为空,则可能是其他线程正在修改节点。比如上面说的弱一致迭代器在将指针更改为新值的过程。而之前的 get操作都未进行锁定,根据bernstein条件,读后写或写后读都会引起数据的不一致,所以这里要对这个e重新上锁再读一遍,以保证得到的是正确值。readValueUnderLock中就是用了lock()进行加锁。

put操作已开始就锁住了整个segment。这是因为修改操作时不能并发的。

同样,remove操作也是如此(类似put,一开始就锁住真个segment)。

但要注意一点区别,中间那个for循环是做什么用的呢?(截图未完全,可以自己找找代码查看一下)。从代码来看,就是将定位之后的所有entry克隆并拼回前面去,但有必要吗?每次删除一个元素就要将那之前的元素克隆一遍?这点其实是由entry的不变性来决定的,仔细观察entry定义,发现除了value,其他 所有属性都是用final来修饰的,这意味着在第一次设置了next域之后便不能再改变它,取而代之的是将它之前的节点全都克隆一次。至于entry为什么要设置为不变性,这跟不变性的访问不需要同步从而节省时间有关。


http://chatgpt.dhexx.cn/article/49ipoKpn.shtml

相关文章

ConcurrentHashMap 面试题

作者:程序员库森 链接:https://www.nowcoder.com/discuss/591527?source_idprofile_create_nctrack&channel-1 来源:牛客网 本文汇总了常考的 ConcurrentHashMap 面试题,面试 ConcurrentHashMap,看这一篇就够了…

Hashmap和ConcurrentHashmap的区别

HashTable (1)底层数组链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化 (2&#xff0…

ConcurrentHashMap的作用与用法

ConcurrentHashMap的作用与用法 一.ConcurrentHashMap简介 ConcurrentHashMap是属于JUC工具包中的并发容器之一,在多线程开发中很经常会使用到这个类,它与HashMap的区别是HashMap是线程不安全的,在高并发的情况下,使用HashMap进行…

Java并发包concurrent——ConcurrentHashMap

目录 1. ConcurrentHashMap的实现——JDK7版本 1.1 分段锁机制 1.2 ConcurrentHashMap的数据结构 1.3 ConcurrentHashMap的初始化 1.3.1 初始化ConcurrentHashMap 1.3.2 初始化Segment分段 1.4 定位Segment 1.5 ConcurrentHashMap的操作 1.5.1 get 1.5.2 put 1.5.3 …

Java8 ConcurrentHashMap详解

点个赞,看一看,好习惯!本文 GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了 3 个月总结的一线大厂 Java 面试总结,本人已拿大厂 offer。 另外,原创文章首发在我的个人博客&#x…

HashMap与ConcurrentHashMap的区别

从JDK1.2起,就有了HashMap,正如前一篇文章所说,HashMap不是线程安全的,因此多线程操作时需要格外小心。 在JDK1.5中,伟大的Doug Lea给我们带来了concurrent包,从此Map也有安全的了。 ConcurrentHashMap具体…

concurrenthashmap实现原理

1.JDK 1.7 ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成 Segment 继承自 ReentrantLock&#xff0c;是一种可重入锁&#xff1b;其中&#xff0c;HashEntry 是用于真正存储数据的地方 static final class Segment<K,V> extends ReentrantLock i…

HashMap和ConcurrentHashMap

前言 Map 这样的 Key Value 在软件开发中是非常经典的结构&#xff0c;常用于在内存中存放数据。 本篇主要想讨论 ConcurrentHashMap 这样一个并发容器&#xff0c;在正式开始之前我觉得有必要谈谈 HashMap&#xff0c;没有它就不会有后面的 ConcurrentHashMap。 Hash 表 在…

深入浅出ConcurrentHashMap详解

文章目录 1、前言2、什么是ConcurrentHashMap3、Put 操作4、Get 操作5、高并发线程安全6、JDK8 的改进6.1 结构改变6.2 HashEntry 改为 Node6.3 Put 操作的变化6.4 Get 操作的变化6.5 总结 1、前言 学习本章之前&#xff0c;先学习&#xff1a;深入浅出HashMap详解&#xff08;…

ConcurrentHashMap

ConcurrentHashMap 1.ConcurrentHashMap的出现 我们最常用的集合框架一定包括HashMap&#xff0c;但是都知道它不是线程安全的。在并发插入元素的时候&#xff0c;有可能出现带环链表&#xff0c;让下一次读操作出现死循环。 而想要次避免HashMap的线程安全问题有很多办法&am…

ConcurrentHashMap详解

文章目录 什么是ConcurrentHashMapConcurrentHashMap结构如何高效的执行并发操作如何进行锁的选择Node节点类型与作用扩容的方式 源码分析putVal()方法spread()方法&#xff0c;获取槽位。initTable()方法&#xff0c;初始化容器addCount() &#xff0c;计算成员数量transfer()…

Hudi(四)集成Flink(2)

6、读取方式 6.1、流读&#xff08;Streaming Query&#xff09; 当前表默认是快照读取&#xff0c;即读取最新的全量快照数据并一次性返回。通过参数 read.streaming.enabled 参数开启流读模式&#xff0c;通过 read.start-commit 参数指定起始消费位置&#xff0c;支持指定 …

Spring Boot锦集(三):Spring Boot整合Kafka | Zookeeper/Kafka的安装和配置 | 总结的很详细

前言 在学习本章节前&#xff0c;务必做好以下准备工作&#xff1a; 1、安装并启动了Zookeeper[官网]&#xff0c;如需帮助&#xff0c;点击进入&#xff1b; 2、安装并启动了Kafka[官网]&#xff0c;如需帮助&#xff0c;点击进入。 注&#xff1a;zk和kafka的安装与介绍&…

Flink系列之:Flink CDC深入了解MySQL CDC连接器

Flink系列之&#xff1a;Flink CDC深入了解MySQL CDC连接器 一、增量快照特性1.增量快照读取2.并发读取3.全量阶段支持 checkpoint4.无锁算法5.MySQL高可用性支持 二、增量快照读取的工作原理三、全量阶段分片算法四、Chunk 读取算法五、Exactly-Once 处理六、MySQL心跳事件支持…

大数据面试重点之kafka(三)

Kafka如何保证全局有序&#xff1f; 可回答&#xff1a;1&#xff09;Kafka消费者怎么保证有序性&#xff1f;2&#xff09;Kafka生产者写入数据怎么保证有序&#xff1f;3&#xff09;Kafka可以保证 数据的局部有序&#xff0c;如何保证数据的全局有序&#xff1f;4&#xff0…

Apache Kafka-auto.offset.reset参数(earliest、latest、none)含义说明

文章目录 官方说明参数解读CodePOM依赖配置文件生产者消费者单元测试测试earliestlatest(默认&#xff09;noneexception 源码地址 官方说明 https://kafka.apache.org/documentation/ 选择对应的版本&#xff0c;我这里选的是 2.4.X https://kafka.apache.org/24/documenta…

Kafka之auto.offset.reset值解析

今日在使用kafka时&#xff0c;发现将 auto.offset.reset 设置为earliest、latest、none 都没有达到自己预期的效果。 earliest&#xff1a; 当各分区下有已提交的offset时&#xff0c;从提交的offset开始消费&#xff1b;无提交的offset时&#xff0c;从头开始消费latest&…

关于EarlyZ

在前向渲染中&#xff0c;ZTest是在Fragement Shader之后进行的&#xff0c;也就是说&#xff0c;被遮挡的部分也要绘制FS&#xff0c;就产生了Over Draw&#xff0c;其实很费&#xff0c;Early Z Culling就解决了这个问题 Early fragment tests, as an optimization, exist t…

【EARLIER/EARLIEST函数】引用不存在的更早的行上下文 报错解决

引用PowerQuery的例子并给予个人理解 X1 SUMX(FILTER(Data,Data[订单日期]>EARLIER(Data[订单日期])),[金额])---WRONG X2CALCULATE(SUM(Data[金额]),FILTER(Data,SUMX(FILTER(Data,Data[订单日期]>EARLIER(Data[订单日期])),[金额])))---RIGHT X1报错原因&#xff1a…

EarlyStop

在训练中&#xff0c;我们希望在中间箭头的位置停止训练。而Early stopping就可以实现该功能&#xff0c;这时获得的模型泛化能力较强&#xff0c;还可以得到一个中等大小的w的弗罗贝尼乌斯范数。其与L2正则化相似&#xff0c;选择参数w范数较小的神经网络。 可以用L2正则化代…