CurrentHashMap的实现原理

网友投稿 287 2022-11-18

CurrentHashMap的实现原理

我们熟知的缓存技术(比如redis、memcached)的核心其实就是在内存中维护一张巨大的哈希表,还有大家熟知的HashMap、CurrentHashMap等的应用。

文章目录

​​ConcurrentHashMap与HashMap等的区别​​

​​HashMap​​​​HashTable​​

​​ConcurrentHashMap​​

​​JDK1.7版本的CurrentHashMap的实现原理​​​​JDK1.8版本的CurrentHashMap的实现原理​​

​​总结​​

ConcurrentHashMap与HashMap等的区别

HashMap

我们知道HashMap是线程不安全的,在多线程环境下,使用Hashmap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap。

HashTable

HashTable和HashMap的实现原理几乎一样,差别无非是

HashTable不允许key和value为null HashTable是线程安全的 但是HashTable线程安全的策略实现代价却太大了,简单粗暴,get/put所有相关操作都是synchronized的,这相当于给整个哈希表加了一把大锁。

多线程访问时候,只要有一个线程访问或操作该对象,那其他线程只能阻塞,相当于将所有的操作串行化,在竞争激烈的并发场景中性能就会非常差。

ConcurrentHashMap

主要就是为了应对hashmap在并发环境下不安全而诞生的,ConcurrentHashMap的设计与实现非常精巧,大量的利用了volatile,final,CAS等lock-free技术来减少锁竞争对于性能的影响。 我们都知道Map一般都是数组+链表结构(JDK1.8该为数组+红黑树)。

ConcurrentHashMap避免了对全局加锁改成了局部加锁操作,这样就极大地提高了并发环境下的操作速度,由于ConcurrentHashMap在JDK1.7和1.8中的实现非常不同,接下来我们谈谈JDK在1.7和1.8中的区别。

JDK1.7版本的CurrentHashMap的实现原理

在JDK1.7中ConcurrentHashMap采用了数组+Segment+分段锁的方式实现。

ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表,同时又是一个ReentrantLock(Segment继承了ReentrantLock)。

内部结构图

第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部。

该结构的优劣势

坏处是这一种结构的带来的副作用是Hash的过程要比普通的HashMap要长。

好处是写操作的时候可以只对元素所在的Segment进行加锁即可,不会影响到其他的Segment,这样,在最理想的情况下,ConcurrentHashMap可以最高同时支持Segment数量大小的写操作(刚好这些写操作都非常平均地分布在所有的Segment上)。 所以,通过这一种结构,ConcurrentHashMap的并发能力可以大大的提高。

JDK1.8版本的CurrentHashMap的实现原理

synchronized+cas+node+红黑树的实现方式来设计,内部大量采用CAS操作,Node中的val和next都有volatle修饰。保证了原子性。

JDK8中彻底放弃了Segment转而采用的是Node,其设计思想也不再是JDK1.7中的分段锁思想。

查找,替换,赋值的操作都有CAS

class Node implements Map.Entry { final int hash; final K key; volatile V val; volatile Node next; //... 省略部分代码}

Java8 ConcurrentHashMap结构基本上和Java8的HashMap一样,不过保证线程安全性。

总结

其实可以看出JDK1.8版本的ConcurrentHashMap的数据结构已经接近HashMap,相对而言,ConcurrentHashMap只是增加了同步的操作来控制并发,从JDK1.7版本的ReentrantLock+Segment+HashEntry,到JDK1.8版本中synchronized+CAS+HashEntry+红黑树。

1.数据结构:取消了Segment分段锁的数据结构,取而代之的是数组+链表+红黑树的结构。 2.保证线程安全机制:JDK1.7采用segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock。JDK1.8采用CAS+Synchronized保证线程安全。 3.锁的粒度:原来是对需要进行数据操作的Segment加锁,现调整为对每个数组元素加锁(Node)。 4.链表转化为红黑树:定位结点的hash算法简化会带来弊端,Hash冲突加剧,因此在链表节点数量大于8时,会将链表转化为红黑树进行存储。 5.查询时间复杂度:从原来的遍历链表O(n),变成遍历红黑树O(logN)。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:商务百搭创基USB-C扩展坞转接无限可能
下一篇:java向数据库插入数据显示乱码的几种问题解决
相关文章

 发表评论

暂时没有评论,来抢沙发吧~