当前位置:首页 >时尚 >再次聊聊并发编程:并发容器 实现了NavigableMap接口

再次聊聊并发编程:并发容器 实现了NavigableMap接口

2024-07-01 11:30:32 [百科] 来源:避面尹邢网

再次聊聊并发编程:并发容器

作者:日拱一卒程序猿 开发 前端 ConcurrentHashMap 是再次一种 key 无序的 HashMap,ConcurrentSkipListMap则是聊聊 key 有序的, 实现了NavigableMap接口,并发编程并此接口又继承了SortedMap接口。容器

一、再次ConcurrentLinkedQueue/Deque

AQS内部的聊聊阻塞队列实现原理:基于双向链表,通过对head/tail进行CAS操作,并发编程并实现入队和出队。容器

ConcurrentLinkedQueue 的再次实现原理和AQS 内部的阻塞队列类似:同样是基于 CAS,同样是聊聊通过 head/tail指针记录队列头部和尾部,但还是并发编程并有稍许差别。

再次聊聊并发编程:并发容器 实现了NavigableMap接口

其次,容器在AQS的再次阻塞队列中,每次入队后,聊聊tail一定后移一个位置;每次出队,并发编程并head一定后移一个 位置,以保证head指向队列头部,tail指向链表尾部。

再次聊聊并发编程:并发容器 实现了NavigableMap接口

但在ConcurrentLinkedQueue中,head/tail的更新可能落后于节点的入队和出队,因为它不是直 接对 head/tail指针进行 CAS操作的,而是对 Node中的 item进行操作。

再次聊聊并发编程:并发容器 实现了NavigableMap接口

二、ConcurrentHashMap

HashMap通常的实现方式是“数组+链表”,这种方式被称为“拉链法”。ConcurrentHashMap在这个 基本原理之上进行了各种优化。

首先是所有数据都放在一个大的HashMap中;其次是引入了红黑树。

如果头节点是Node类型,则尾随它的就是一个普通的链表;如果头节点是TreeNode类型,它的后 面就是一棵红黑树,TreeNode是Node的子类。

链表和红黑树之间可以相互转换:初始的时候是链表,当链表中的元素超过某个阈值时,把链表转 换成红黑树;反之,当红黑树中的元素个数小于某个阈值时,再转换为链表。

那为什么要做这种设计呢?

1. 使用红黑树,当一个槽里有很多元素时,其查询和更新速度会比链表快很多,Hash冲突的问 题由此得到较好的解决。

2. 加锁的粒度,并非整个ConcurrentHashMap,而是对每个头节点分别加锁,即并发度,就是 Node数组的长度,初始长度为16。

3. 并发扩容,这是难度最大的。当一个线程要扩容Node数组的时候,其他线程还要读写,因此 处理过程很复杂,后面会详细分析。

由上述对比可以总结出来:这种设计一方面降低了Hash冲突,另一方面也提升了并发度。

三、ConcurrentSkipListMap/Set

ConcurrentHashMap 是一种 key 无序的 HashMap,ConcurrentSkipListMap则是 key 有序的, 实现了NavigableMap接口,此接口又继承了SortedMap接口。

1、ConcurrentSkipListMap

为什么要使用SkipList实现Map?

在Java的util包中,有一个非线程安全的HashMap,也就是TreeMap,是key有序的,基于红黑树实 现。 而在Concurrent包中,提供的key有序的HashMap,也就是ConcurrentSkipListMap,是基于 SkipList(跳查表)来实现的。

这里为什么不用红黑树,而用跳查表来实现呢?

也就是目前计算机领域还未找到一种高效的、作用在树上的、无锁的、增加和删除节点的办法。

2、ConcurrentSkipListSet

ConcurrentSkipListSet只是对ConcurrentSkipListMap的简单封装。

责任编辑:武晓燕 来源: 今日头条 并发编程并发容器

(责任编辑:热点)

    推荐文章
    热点阅读