博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
并发编程系列:ConcurrentHashMap的实现原理详解(JDK1.7和JDK1.8)
阅读量:6222 次
发布时间:2019-06-21

本文共 2655 字,大约阅读时间需要 8 分钟。

hot3.png

HashMap、CurrentHashMap 的实现原理基本都是BAT面试必考内容,我在历史博文《阿里P8架构师谈:深入探讨HashMap的底层结构、原理、扩容机制》中曾深入谈过hashmap的实现原理,今天主要谈CurrentHashMap的实现原理。

内容目录:

1.哈希表

2.ConcurrentHashMap与HashMap、HashTable的区别

3.CurrentHashMap在JDK1.7和JDK1.8版本的区别

哈希表

1.介绍

哈希表(Hash table),根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

哈希表设计了一个映射关系f(key)= address,根据key来计算存储地址address,这样可以1次查找,f既是存储数据过程中用来指引数据存储到什么位置的函数,也是将来查找这个位置的算法,叫做哈希算法。

2.应用场景

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

ConcurrentHashMap与HashMap等的区别

1.HashMap

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

2.HashTable

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

  • HashTable不允许key和value为null
  • HashTable是线程安全的

但是HashTable线程安全的策略实现代价却太大了,简单粗暴,get/put所有相关操作都是synchronized的,这相当于给整个哈希表加了一把大锁,多线程访问时候,只要有一个线程访问或操作该对象,那其他线程只能阻塞,相当于将所有的操作串行化,在竞争激烈的并发场景中性能就会非常差。

3.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)。

ConcurrentHashMap使用分段锁技术,将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问,能够实现真正的并发访问。如下图是ConcurrentHashMap的内部结构图:

并发编程系列:ConcurrentHashMap的实现原理(JDK1.7和JDK1.8)

 

从上面的结构我们可以了解到,ConcurrentHashMap定位一个元素的过程需要进行两次Hash操作。

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

因此,这一种结构的带来的副作用是Hash的过程要比普通的HashMap要长,但是带来的好处是写操作的时候可以只对元素所在的Segment进行加锁即可,不会影响到其他的Segment,这样,在最理想的情况下,ConcurrentHashMap可以最高同时支持Segment数量大小的写操作(刚好这些写操作都非常平均地分布在所有的Segment上)。

所以,通过这一种结构,ConcurrentHashMap的并发能力可以大大的提高。

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

JDK8中ConcurrentHashMap参考了JDK8 HashMap的实现,采用了数组+链表+红黑树的实现方式来设计,内部大量采用CAS操作,JDK8中彻底放弃了Segment转而采用的是Node,其设计思想也不再是JDK1.7中的分段锁思想。

在JDK8中ConcurrentHashMap的结构,由于引入了红黑树,使得ConcurrentHashMap的实现非常复杂,我们都知道,红黑树是一种性能非常好的二叉查找树,其查找性能为O(logN),但是其实现过程也非常复杂,而且可读性也非常差,Doug Lea的思维能力确实不是一般人能比的,早期完全采用链表结构时Map的查找时间复杂度为O(N),JDK8中ConcurrentHashMap在链表的长度大于某个阈值的时候会将链表转换成红黑树进一步提高其查找性能。

并发编程系列:ConcurrentHashMap的实现原理(JDK1.7和JDK1.8)

总结

1, 从JDK1.7到1.8,ConcurrentHashMap 的结构从ReentrantLock+Segment+HashEntry变化为synchronized+CAS+HashEntry+红黑树。

2.在扩容的情况下,哈希冲突得到一定的处理,提高了效率。

3.在JDK1.8中ConcurrentHashMap和HashMap一样,采取了红黑树结构,和链表选择使用,提高了遍历的速度。

以上是ConcurrentHashMap的实现原理介绍。

我往期整理的【高并发架构详解系列文章66期完整集合】,感兴趣的童鞋了解下,发送【高并发】给公众号【mikechen优知】即可获得。

 

觉得不错请点赞支持,欢迎留言或进我的个人群领取【架构资料专题目合集90期】、【BATJTMD大厂JAVA面试真题1000+】,本群专用于学习交流技术、分享面试机会,拒绝广告,我也会在群内不定期答题、探讨。

 

 

 

转载于:https://my.oschina.net/jiagouzhan/blog/2992405

你可能感兴趣的文章
innodb重做日志缓冲
查看>>
大数据系列之大数据分析如何权衡存储
查看>>
软件系统开发的过程是怎么样的?分为几个步骤?
查看>>
Spark-Spark Streaming例子整理(一)
查看>>
projecteuler_problem2
查看>>
10大托管国家和5大危险电子邮件主题
查看>>
基于对偶学习的跨领域图片描述生成
查看>>
Docker收购SDN技术创业公司SocketPlane
查看>>
WCF技术剖析之十二:数据契约(Data Contract)和数据契约序列化器(DataContractSerializer)...
查看>>
深入剖析 iLBC 编码器原理
查看>>
sprintf你知道多少(转)
查看>>
2017“CCF科学技术奖”全公布,6位获奖人带来独家经验分享
查看>>
Go嵌入类型及内部提升样例
查看>>
关于js中单双引号以及转义符的理解
查看>>
OpenCASCADE Interpolation - Lagrange
查看>>
王国军:与YOCSEF一起走过的日子
查看>>
ICCV 2017 spotlight论文解读:如何提高行人再识别的准确率
查看>>
DockOne微信分享(一三九):基于Kubernetes的应用编排实践
查看>>
nginx日志分析
查看>>
思科放弃机顶盒业务 转而聚焦云视频传输领域
查看>>