Java | ConcurrentHashMap

Java7:

ConcurrentHashMap在内部细分为若干个小的HashMap,叫做数据段Segment。默认情况下,一个ConcurrentHashMap被细分为16个Segment,对每个Segment的数据都单独进行加锁操作。Segment的个数则为锁的并发度。

ConcurrentHashMap是由Segment数组和HashEntry数组组成的。Segment继承了可重入锁ReentrantLock,它在ConcurrentHashMap里扮演锁的角色。HashEntry则用于存储键值对数据。

在每一个ConcurrentHashMap里都包含一个Segment数组,Segment的结构和HashMap类似,是数组和链表结构。在每个Segment里都包含一个HashEntry数组,每个HashEntry都是一个链表结构的数据,每个Segment都守护一个HashEntry数组里的元素,在对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。

在操作ConcurrentHashMap时,如果需要在其中添加一个新的数据,则并不是将整个HashMap加锁,而是先根据HashCode查询该数据应该被存放在哪个Segment,然后对该Segment加锁并完成put操作。在多线程并发情况下, 只要加入的数据被存放在不同的Segment中,线程间就可以做到并行的线程安全。

 

JDK8与JDK7中ConcurrentHashMap的区别:

多线程并发环境下锁机制:

JDK7中ConcurrentHashMap主要对整个桶数组进行了分割分段即Segment,每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。

JDK8中使用的是优化的synchronized 关键字同步代码块 和 CAS原子操作维护并发。

数据结构:

JDK7中ConcurrentHashMap使用使用 Segment数组 + HashEntry数组 + 链表。一个Segments数组,存储一个Segments对象,一个Segments中储存一个Entry数组,存储的每个Entry对象又是一个链表头结点。

数据结构:

而JDK8中使用 Node数组+链表+ 红黑树,Node数组使用来存放树或者链表的头结点,当一个链表中的数量到达一个数目时,会使查询速率降低,所以到达一定阈值时,会将一个链表转换为一个红黑二叉树,通告查询的速率。

 

 效率:

首先HashMap多线程环境下不安全。而Hashtable使用的是synchronized方法锁,若一个线程抢夺了锁,其他线程只能等到持锁线程操作完成之后才能抢锁操作。

对于ConcurrentHashMap:

JDK7中使用的分段锁,只要加入的数据被存放在不同的Segment中,线程间就可以做到并行的线程安全。

JDK8中put()和get()不用二次哈希,一把锁只锁住一个链表或者一棵树,并发效率更加提升。

 

 

实际上JDK8中ConcurrentHashMap已经不采用Segment锁机制,虽然有内部类Segment,单实际上没什么作用。而是采用synchronized+CAS原子操作来确保并发的安全。

 

ConcurrentHashMap在JDK7与JDK8中的不同: 

https://blog.csdn.net/qq_41884976/article/details/89532816

https://www.jianshu.com/p/5dbaa6707017

 

学习中~ ,后续补充~ 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章