HashMap、HashTable、CurrentHashMap对比

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

一、HashMapHashTableCurrentHashMap对比

1.1 CurrentHashMapHashMap对比

ConcurrentHashMap就是为了HashMap在多线程下不安全而诞生的,它大量的使用了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结构图:
HashMap、HashTable、CurrentHashMap对比_第1张图片

从上面的结构我们可以看出,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)

你可能感兴趣的:(Java,java,开发语言)