concurrenthashmap

来源:互联网 发布:星野扒皮知乎 编辑:程序博客网 时间:2024/05/19 13:22

ConcurrentHashMap

1 JDK6与JDK7中的实现

1.1 设计思路与并发度

ConcurrentHashMap是并发容器,使用锁分段技术来保证线程安全的(ConcurrentHashMap是弱一致性的)。
ConcurrentHashMap默认的并发度为16,但用户也可以在构造函数中设置并发度。当用户设置并发度时,ConcurrentHashMap会使用大于等于该值的最小2幂指数作为实际并发度(假如用户设置并发度为17,实际并发度则为32)。
它的数据结构是:
内部有一个segment[]数组,Segment类继承于ReentrantLock类,所以Segment本质上是一个可重入的互斥锁。Segment类中存在HashEntry[]数组,HashEntry是单链表结构。

1、get操作

它首先根据key计算出来的哈希值,获取key所对应的Segment片段。如果不为空,则在Segment片段的HashEntry数组中找到key所对应的HashEntry链表,然后遍历该链表。

2、put操作

在插入前会获取Segment对应的互斥锁,插入后会释放锁。
根据key获取对应的哈希值,再根据哈希值找到对应的Segment片段。如果Segment片段不存在,则新增一个Segment。将key-value键值对添加到Segment片段中。
若在遍历HashEntry链表时,找到与“key-value键值对”对应的节点,即“要插入的key-value键值对”的key已经存在于HashEntry链表中。则根据onlyIfAbsent进行判断,若onlyIfAbsent为true,即“当要插入的key不存在时才插入”,则不进行插入,直接返回;否则,用新的value值覆盖原始的value值,然后再返回。

若在遍历HashEntry链表时,没有找到与“要key-value键值对”对应的节点。当node!=null时,即在scanAndLockForPut()获取锁时,已经新建了key-value对应的HashEntry节点,则”将HashEntry添加到Segment中“;否则,新建key-value对应的HashEntry节点,然后再“将HashEntry添加到Segment中”。 在”将HashEntry添加到Segment中“前,会判断是否需要rehash。如果在添加key-value键值之后,容量会超过阈值,并且HashEntry数组的长度没有超过限制,则进行rehash;否则,直接通过setEntryAt()将key-value键值对添加到Segment中。

3、扩容方式

jdk1.8的不同

1、不再用Segment类,代码中保留它的目的是为了序列化兼容。加锁的粒度变为了链表节点。
2、
3、当链表长度超过了一定阈值,在扩容的过程中将链表结构变为红黑树结构。

0 0
原创粉丝点击