ConcurrentSkipListMap深入分析
1.前言
ConcurrentHashMap与ConcurrentSkipListMap性能测试
在4线程1.6万数据的条件下,ConcurrentHashMap 存取速度是ConcurrentSkipListMap 的4倍左右。但ConcurrentSkipListMap有几个ConcurrentHashMap 不能比拟的优点:
ConcurrentSkipListMap 的key是有序的。
ConcurrentSkipListMap 支持更高的并发。ConcurrentSkipListMap 的存取时间是log(N),和线程数几乎无关。也就是说在数据量一定的情况下,并发的线程越多,ConcurrentSkipListMap越能体现出他 的优势
2.使用建议
在非多线程的情况下,应当尽量使用TreeMap。此外对于并发性相对较低的并行程序可以使用 Collections.synchronizedSortedMap将TreeMap进行包装,也可以提供较好的效率。对于高并发程序,应当使用 ConcurrentSkipListMap,能够提供更高的并发度。
所以在多线程程序中,如果需要对Map的键值进行排序时,请尽量使用ConcurrentSkipListMap,可能得到更好的并发度。
注意,调用ConcurrentSkipListMap的size时,由于多个线程可以同时对映射表进行操作,所以映射表需要遍历整个链表才能返回元素个数,这个操作是个O(log(n))的操作。
3.什么是SkipList
Skiplist(跳表)是一种可以代替平衡树的数据结构,默认是按照Key值升序的。Skiplist让已排序的数据分布在多层链表中,以0-1随机数决定一个数据的向上攀升与否,通过“空间来换取时间”的一个算法,在每个节点中增加了向前的指针,在插入、删除、查找时可以忽略一些不可能涉及到的结点,从而提高了效率。
从概率上保持数据结构的平衡比显示的保持数据结构平衡要简单的多。对于大多数应用,用Skip list要比用树算法相对简单。由于Skip list比较简单,实现起来会比较容易,虽然和平衡树有着相同的时间复杂度(O(logn)),但是skip list的常数项会相对小很多。Skiplist在空间上也比较节省。一个节点平均只需要1.333个指针(甚至更少)。
图1-1 Skip list结构图(以7,14,21,32,37,71,85序列为例)
Skip list的性质
(1) 由很多层结构组成,level是通过一定的概率随机产生的。
(2) 每一层都是一个有序的链表,默认是升序,也可以根据创建映射时所提供的Comparator
进行排序,具体取决于使用的构造方法。
(3) 最底层(Level 1)的链表包含所有元素。
(4) 如果一个元素出现在Level i 的链表中,则它在Level i 之下的链表也都会出现。
(5) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。
三、什么是ConcurrentSkipListMap
ConcurrentSkipListMap提供了一种线程安全的并发访问的排序映射表。内部是SkipList(跳表)结构实现,在理论上能够在O(log(n))时间内完成查找、插入、删除操作。
注意,调用ConcurrentSkipListMap的size时,由于多个线程可以同时对映射表进行操作,所以映射表需要遍历整个链表才能返回元素个数,这个操作是个O(log(n))的操作。
ConcurrentSkipListMap存储结构
ConcurrentSkipListMap存储结构图
跳跃表(SkipList):(如上图所示)
1.多条链构成,是关键字升序排列的数据结构;
2.包含多个级别,一个head引用指向最高的级别,最低(底部)的级别,包含所有的key;
3.每一个级别都是其更低级别的子集,并且是有序的;
4.如果关键字 key在 级别level=i中出现,则,level<=i的链表中都会包含该关键字key;
------------------------
ConcurrentSkipListMap主要用到了Node和Index两种节点的存储方式,通过volatile关键字实现了并发的操作
- staticfinalclass
final
volatile - volatile
- staticclass
final
final - volatile
- }
------------------------
ConcurrentSkipListMap的查找
通过SkipList的方式进行查找操作:(下图以“查找91”进行说明:)
红色虚线,表示查找的路径,蓝色向右箭头表示right引用;黑色向下箭头表示down引用;
/get方法,通过doGet操作实现
- public
return - private
super
null - int
for - ifnullnull
if) { - continue
elseif) { - returnnull
else - ifnull
else
break - fornull
ifnull
if) { - returnnull
elseif) - break
returnnull
}
------------------------------------------------
ConcurrentSkipListMap的删除
通过SkipList的方式进行删除操作:(下图以“删除23”进行说明:)
红色虚线,表示查找的路径,蓝色向右箭头表示right引用;黑色向下箭头表示down引用;
- //remove操作,通过doRemove实现,把所有level中出现关键字key的地方都delete掉
public
returnnullfinal
super
for - for
- ifnull//如果next引用为空,直接返回
returnnullif
- break
ifnull
- break
ifnull
- break
int
if) - returnnull
if) { - continue
ifnull
returnnull
ifnull
break
if - else
- ifnull
- return
}
-------------------------------------
ConcurrentSkipListMap的插入
通过SkipList的方式进行插入操作:(下图以“添加55”的两种情况,进行说明:)
在level=2(该level存在)的情况下添加55的图示:只需在level<=2的合适位置插入55即可
--------
在level=4(该level不存在,图示level4是新建的)的情况下添加55的情况:首先新建level4,然后在level<=4的合适位置插入55
-----------
- //put操作,通过doPut实现
public
ifnull
thrownew
returnfalseprivateboolean
super
for - for
ifnullif
- break
ifnull
- break
ifnull
- break
int
if) { - continue
if) {
- if
return
else
break - new
if
break - int
- if)
- returnnull
* 获得一个随机的level值
- */
privateint
int
; - ;
- ;
- if) != )
- return;
- int;
- while) & ) != ) ++level;
- return
//执行插入操作:如上图所示,有两种可能的情况:
//1.当level存在时,对level<=n都执行insert操作
//2.当level不存在(大于目前的最大level)时,首先添加新的level,然后在执行操作1
privatevoidintint
if - null
forint; i <= level; ++i) - newnull
- else
- ;
- new];
- null
forint; i <= level; ++i) - newnull
int
forint
if - break
forint; j <= level; ++j)
- new
- if
break
/**
- *在1~indexlevel层中插入数据
- */
privatevoidint - int
super
ifnullthrownew - for
intfor
ifnull - int
ifnull
if
breakcontinue
if) {
- continue
if
- if
- return
if
- break
- if) {
- if
return
if
- }
ConcurrentSkipListMap深入分析的更多相关文章
- Java多线程之ConcurrentSkipListMap深入分析(转)
Java多线程之ConcurrentSkipListMap深入分析 一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下, ...
- Java多线程(四)之ConcurrentSkipListMap深入分析
一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下,ConcurrentHashMap 存取速度是ConcurrentSki ...
- 基于跳跃表的 ConcurrentSkipListMap 内部实现(Java 8)
我们知道 HashMap 是一种键值对形式的数据存储容器,但是它有一个缺点是,元素内部无序.由于它内部根据键的 hash 值取模表容量来得到元素的存储位置,所以整体上说 HashMap 是无序的一种容 ...
- 关于ConcurrentSkipListMap的理解
一.前言 JCIP 提到了在 Java 6 中引入了两个新的并发集合类 ConcurrentSkipListMap 和 ConcurrentSkipListSet.其实只要介绍一下 Concurren ...
- (转载)java高并发:CAS无锁原理及广泛应用
java高并发:CAS无锁原理及广泛应用 版权声明:本文为博主原创文章,未经博主允许不得转载,转载请注明出处. 博主博客地址是 http://blog.csdn.net/liubenlong007 ...
- AQS源码深入分析之共享模式-你知道为什么AQS中要有PROPAGATE这个状态吗?
本文基于JDK-8u261源码分析 本篇文章为AQS系列文的第二篇,前文请看:[传送门] 第一篇:AQS源码深入分析之独占模式-ReentrantLock锁特性详解 1 Semaphore概览 共享模 ...
- 深入分析Spring 与 Spring MVC容器
1 Spring MVC WEB配置 Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext类扩展ApplicationContext, ...
- Linux堆内存管理深入分析(下)
Linux堆内存管理深入分析 (下半部) 作者@走位,阿里聚安全 0 前言回顾 在上一篇文章中(链接见文章底部),详细介绍了堆内存管理中涉及到的基本概念以及相互关系,同时也着重介绍了堆中chunk分 ...
- Linux堆内存管理深入分析(上)
Linux堆内存管理深入分析(上半部) 作者:走位@阿里聚安全 0 前言 近年来,漏洞挖掘越来越火,各种漏洞挖掘.利用的分析文章层出不穷.从大方向来看,主要有基于栈溢出的漏洞利用和基于堆溢出的漏洞 ...
随机推荐
- RunTime 给类添加属性
RunTime网上有很多人都不知道Runtime到底是干嘛的?有很多博主都是长篇大论给他们讲这个讲那个,我感觉还不如实例来的实在.很简单的一个例子:我们都知道会有这样的需求,未读消息列表的图片上要有一 ...
- Luogu2723丑数Humble Numbers【归并排序】
Luogu2723丑数Humble Numbers 题目背景 对于一给定的素数集合 S = {p1, p2, ..., pK},考虑一个正整数集合,该集合中任一元素的质因数全部属于S.这个正整数集合包 ...
- 设置ssh只允许用户从指定的IP登陆
假设 我们公司的固定IP是 183.21.89.249 连接上我们自己进行管理的服务器 然后编辑ssh的配置文件默认 /etc/ssh/sshd_config 在文件最后面另起一行添加 ...
- 老李分享:大数据测试之HDFS文件系统
poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821478,咨询电话010-845052 ...
- window.onload与document.ready的区别
1. window.onload必须等到网页中所有的内容加载完(包含图片)才执行 document.ready网页中所有DOM结构绘制完执行,可能DOM并没有加载完 所有document.ready比 ...
- 使用react native制作的一款网络音乐播放器
使用react native制作的一款网络音乐播放器 基于第三方库 react-native-video设计"react-native-video": "^1.0.0&q ...
- sql连接查询中on筛选与where筛选的区别
sql查询这个东西, 要说它简单, 可以很简单, 通常情况下只需使用增删查改配合编程语言的逻辑表达能力,就能实现所有功能. 但是增删查改并不能代表sql语句的所有, 完整的sql功能会另人望而生畏. ...
- C#,VB.NET 如何将Excel转换为Text
在工作中,有时我们需要转换文档的格式,之前已经跟大家介绍过了如何将Excel转换为PDF.今天将与大家分享如何将Excel转换为Text.这次我使用的依然是免费版的Spire.XLS for .NET ...
- 面试题 ARC
什么是ARC ?ARC主要解决什么问题? ARC:自动引用计数. 要点..当对象被创建时 retain count+1, 当对象被release时 retain count-1, 当retain co ...
- .net 读取实体属性和描述注释
.net 读取实体属性和描述注释 class Program { static void Main(string[] args) { TEST test = new TEST(); test.MyNa ...