HashMap、HashTable、CurrentHashMap对比

  • 😜           是江迪呀
  • ✒️本文关键词Java集合MapCurrentHashMap
  • ☀️每日   一言坚持自己的风格,面对未知的一切!

在这里插入图片描述

一、HashMapHashTableCurrentHashMap对比

1.1 CurrentHashMapHashMap对比

由于HashMap在多线程下不安全诞生了HashTable由于HashTable效率太低诞生了CurrentHashMapCurrentHashMap它大量的使用了volatilefinalCASlock-free技术来减少锁竞争对于性能的影响。ConcurrentHashMap避免了对全局加锁改成了局部加锁操作。这样就极大的提高了 并发环境下的操作速度。

所以CurrentHashMap线程是安全的,HashMap线程不安全,在多线程下,使用HashMap进行put操作或造成死循环,导致CPU的利用率接近100%,使用并发情况下不能使用HashMap

1.2 HashMapHashTable对比

HashMapHashTable的实现原理几乎一致,差别是:HashTable不允许keyvaluenull。HashTable是线程安全的。但是Hastable实现线程安全的代价很大,get/put的所有相关操作都是synchronized的,这相当于给hash表加上了一把大锁,多发生多线程操作HashTable时,只要有一个线程操作HashTable其它线程必须阻塞,相当于将所有多线程操作串行化,性能和效率很差。

二、JDK1.7ConcurrentHashMap实现原理

在JDK1.7中ConcurrentHashMap使用的是数组+Segment+分段锁对的方式实现。Segment(分段锁)–减少锁的粒度,ConcurrentHashMap中的分段锁被称为Segment,它类似与 HashMap对的结构,及内部拥有一个Entry数组,数组中的每个元素又是一个链表。同时又是一个ReentrantLock(Segment继承了ReentrantLock

2.1 ConcurrentHashMap的内部结构

ConcurrentHashMap采用分段锁技术,将数据分为一段一段存储, 然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其它段的数据也能被其它线程访问。能够实现真正意义的并发访问,ConcurrentHashMap结构图:
在这里插入图片描述

从上面的结构我们可以看出,ConcurrentHashMap定位一个元素的过程需要进行两次操作。第一次定位到底Segment,第二次定位定位到元素所在的链表的头部。
好处:写操作的时候可以只对元素所在的Segment进行加锁即可,不会影响到 其它的Segment,这样在理想状态下,ConcurrentHashMap可以最高同时支持和Segment数量一样多的写操作(刚好这些写操作都非常平均的分配到,所有的Segment上)并发能力可以大大的提高。
坏处:这种结构带来的副作用就是,存值时的过程要比HashMap要长。Segment的数量是根据并发总量来决定的,比如来说,并发总量是8,那么segment的数量就是8

2.2 为啥JDK1.8版本的ConcurrentHashMap的并发能力可以大大的提高?

JDK8中ConcurrentHashMap采用了数组+链表+红黑树的实现方式来设计,内部采用大量的CAS操作。

CAScompare and swap的缩写,就是比较并交换。CAS是一种基于锁的操作,是乐观锁
锁分为乐观锁悲观锁,悲观锁就是将资源锁住后,等当前获得锁的对象将锁释放后,下一个线程才能访问。而乐观锁采用了宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高。
CAS操作包含三个操作数:
(1)内存位置(V);
(2)预期值(A);
(3)新值(B);
如果内存地址里面的值和A的值是一样的,那么就将内存中的值更新成BCAS是通过无限循环来获取数据的,如果第一轮循环中,a线程获取地址里面的值被b线程修改了,那么a线程需要自旋,到下次循环才有可能被执行。

JDK8中彻底放弃了Segment转而采用的是Node。其设计思想不再是1.7中的分段锁机制。
Node:保存key,value以及key的Hash值的数据结构,其中value和next都是用volatile修饰,保证并发内存的可见性。java8中的ConcurrentHashMap的结构基本和Java8中的HashMap一致,不过保证线程安全。在JDK8中的ConcurrentHashMap引入了红黑树,红黑树是一种性能非常好的二叉查找树,其查找性能是O。当ConcurrentHashMap中的链表的长度大于某个阈值(这个阈值是8)的时候将链表转化为红黑树,以提高查询效率。

三、总结

3.1 JDK1.8的ConcurrentHashMap结构和Hashmap的结构比较

JDK1.8的ConcurrentHashMap结构和Hashmap的结构很接近,只是增加了同步操作来控制并发:

  • JDK1.7采用: 数组+Segment+HashEntry
  • JDK1.8采用: Synchronized+CAS+HashEntry+红黑树

3.2 JDK1.7和JDK1.8中的ConcurrentHashMap的比较:

  • 数据结构:放弃了Segment分段锁机制,采用了数组+链表+红黑树
  • 保证线程安全机制: 1.7采用Segment分段锁机制,其中Segment继承ReentrantLock。1.8采用CAS+Synchronized保证线程安全。
  • 锁的粒度: 1.7采用的对响应进行数据操作的Segment加锁,1.8调整为对每个数组元素进行加锁(node)减小了锁的粒度,提高的性能。
  • 链表转化为红黑树。
  • 查询时间复杂度: 从原来的遍历链表O(n),变成遍历红黑树O(LogN)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

是江迪呀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值