ConcurrentSkipListMap深入分析

时间:2021-10-22 21:34:31

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个指针(甚至更少)。
                ConcurrentSkipListMap深入分析
图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深入分析
ConcurrentSkipListMap存储结构图

跳跃表(SkipList):(如上图所示)
1.多条链构成,是关键字升序排列的数据结构;
2.包含多个级别,一个head引用指向最高的级别,最低(底部)的级别,包含所有的key;
3.每一个级别都是其更低级别的子集,并且是有序的;
4.如果关键字 key在 级别level=i中出现,则,level<=i的链表中都会包含该关键字key;

------------------------

ConcurrentSkipListMap主要用到了Node和Index两种节点的存储方式,通过volatile关键字实现了并发的操作

[java] view
plain
copy
 
  1. staticfinalclass
    final
    volatile
  2. volatile
  3. staticclass
    final
    final
  4. volatile
  5. }

------------------------

ConcurrentSkipListMap的查找


通过SkipList的方式进行查找操作:(下图以“查找91”进行说明:)

ConcurrentSkipListMap深入分析

红色虚线,表示查找的路径,蓝色向右箭头表示right引用;黑色向下箭头表示down引用;

/get方法,通过doGet操作实现

[java] view
plain
copy
 
  1. public
    return
  2. private
    super
    null
  3. int
    for
  4. ifnullnull
    if) {
  5. continue
    elseif) {
  6. returnnull
    else
  7. ifnull

    else
    break

  8. fornull
    ifnull
    if) {
  9. returnnull
    elseif)
  10. break

    returnnull
        }

------------------------------------------------

ConcurrentSkipListMap的删除


通过SkipList的方式进行删除操作:(下图以“删除23”进行说明:)

ConcurrentSkipListMap深入分析

红色虚线,表示查找的路径,蓝色向右箭头表示right引用;黑色向下箭头表示down引用;

[java] view
plain
copy
 
  1. //remove操作,通过doRemove实现,把所有level中出现关键字key的地方都delete掉
    public
    returnnull

    final
    super
    for

  2. for
  3. ifnull//如果next引用为空,直接返回
    returnnull

    if

  4. break

    ifnull

  5. break

    ifnull

  6. break
    int
    if)
  7. returnnull
    if) {
  8. continue

    ifnull
    returnnull
    ifnull
    break
    if

  9. else
  10. ifnull
  11. return

    }

-------------------------------------

ConcurrentSkipListMap的插入

通过SkipList的方式进行插入操作:(下图以“添加55”的两种情况,进行说明:)

ConcurrentSkipListMap深入分析

在level=2(该level存在)的情况下添加55的图示:只需在level<=2的合适位置插入55即可

--------

ConcurrentSkipListMap深入分析

在level=4(该level不存在,图示level4是新建的)的情况下添加55的情况:首先新建level4,然后在level<=4的合适位置插入55

-----------

[java] view
plain
copy
 
  1. //put操作,通过doPut实现
    public
    ifnull
    thrownew
    returnfalse

    privateboolean
    super
    for

  2. for
    ifnull

    if

  3. break

    ifnull

  4. break

    ifnull

  5. break
    int
    if) {
  6. continue

    if) {

  7. if
    return
    else
    break
  8. new
    if
    break
  9. int
  10. if)
  11. returnnull

    * 获得一个随机的level值

  12. */
    privateint
    int
    ;
  13. ;
  14. ;
  15. if) != )
  16. return;
  17. int;
  18. while) & ) != ) ++level;
  19. return

    //执行插入操作:如上图所示,有两种可能的情况:
    //1.当level存在时,对level<=n都执行insert操作
    //2.当level不存在(大于目前的最大level)时,首先添加新的level,然后在执行操作1 
    privatevoidint

    int
    if

  20. null
    forint; i <= level; ++i)
  21. newnull
  22. else
  23. ;
  24. new];
  25. null
    forint; i <= level; ++i)
  26. newnull

    int
    for

    int
    if

  27. break

    forint; j <= level; ++j)

  28. new
  29. if

    break

    /**

  30. *在1~indexlevel层中插入数据
  31. */
    privatevoidint
  32. int
    super
    ifnullthrownew
  33. for
    int

    for
    ifnull

  34. int
    ifnull
    if
    break

    continue

    if) {

  35. continue

    if

  36. if
  37. return

    if

  38. break
  39. if) {
  40. if

    return

    if

  41. }

ConcurrentSkipListMap深入分析的更多相关文章

  1. Java多线程之ConcurrentSkipListMap深入分析&lpar;转&rpar;

    Java多线程之ConcurrentSkipListMap深入分析   一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下, ...

  2. Java多线程(四)之ConcurrentSkipListMap深入分析

    一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下,ConcurrentHashMap 存取速度是ConcurrentSki ...

  3. 基于跳跃表的 ConcurrentSkipListMap 内部实现(Java 8)

    我们知道 HashMap 是一种键值对形式的数据存储容器,但是它有一个缺点是,元素内部无序.由于它内部根据键的 hash 值取模表容量来得到元素的存储位置,所以整体上说 HashMap 是无序的一种容 ...

  4. 关于ConcurrentSkipListMap的理解

    一.前言 JCIP 提到了在 Java 6 中引入了两个新的并发集合类 ConcurrentSkipListMap 和 ConcurrentSkipListSet.其实只要介绍一下 Concurren ...

  5. &lpar;转载&rpar;java高并发:CAS无锁原理及广泛应用

    java高并发:CAS无锁原理及广泛应用   版权声明:本文为博主原创文章,未经博主允许不得转载,转载请注明出处. 博主博客地址是 http://blog.csdn.net/liubenlong007 ...

  6. AQS源码深入分析之共享模式-你知道为什么AQS中要有PROPAGATE这个状态吗?

    本文基于JDK-8u261源码分析 本篇文章为AQS系列文的第二篇,前文请看:[传送门] 第一篇:AQS源码深入分析之独占模式-ReentrantLock锁特性详解 1 Semaphore概览 共享模 ...

  7. 深入分析Spring 与 Spring MVC容器

    1 Spring MVC WEB配置 Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext类扩展ApplicationContext, ...

  8. Linux堆内存管理深入分析(下)

     Linux堆内存管理深入分析 (下半部) 作者@走位,阿里聚安全 0 前言回顾 在上一篇文章中(链接见文章底部),详细介绍了堆内存管理中涉及到的基本概念以及相互关系,同时也着重介绍了堆中chunk分 ...

  9. Linux堆内存管理深入分析&lpar;上&rpar;

    Linux堆内存管理深入分析(上半部) 作者:走位@阿里聚安全   0 前言 近年来,漏洞挖掘越来越火,各种漏洞挖掘.利用的分析文章层出不穷.从大方向来看,主要有基于栈溢出的漏洞利用和基于堆溢出的漏洞 ...

随机推荐

  1. facebook 用curl获取用户资料

    用facebook获取用户信息 $graph_url= "https://graph.facebook.com/me?scope=email&fields=id,name,email ...

  2. SQL中对于两个不同的表中的属性取差集except运算

    SQL中对两个集合取差集运算,使用except关键字,语法格式如下: SELECT column_name(s) FROM table_name1 EXCEPT SELECT column_name( ...

  3. MS SQL Server2014链接MS SQL Server 2000

    开发与企业应用中,好几个版本SQL Server相互链接.分布式读取与存储,需要实现sp_addlinkedserver.SQL Server 2000, SQL Server 2008, SQL S ...

  4. WordPress 3&period;8&period;1 &sol;xmlrpc&period;php拒绝服务漏洞

    漏洞版本: WordPress 3.8.1 漏洞描述: WordPress是一款内容管理系统. WordPress 3.8.1 /xmlrpc.php 文件有ping其他主机的功能,通过这个功能可以请 ...

  5. Mac常用目录

    服务存放目录: ~/Library/Services/ Xcode代码片段目录 ~/Library/Developer/Xcode/UserData/CodeSnippets

  6. Android经常使用开源组件汇总

    http://www.cnblogs.com/scige/p/3456790.html UI相关 图片 Android-Universal-Image-Loader:com.nostra13.univ ...

  7. Mac 搭建svn本地服务端

    首先建立一个svn目录,位置可以随意,以桌面为例 $ mkdir ~/Desktop/svn 新建一个名为proj的目录作为一个repository $ cd ~/Desktop/svn $ mkdi ...

  8. Linux-监控目录及文件

    Linux-通过inotifywait监控目录及文件 inotifywait命令的使用此处就不写了:可以参考文章:https://www.cnblogs.com/martinzhang/p/41269 ...

  9. 弹性盒子模型属性之flex-shrink

    上一次,我们已经了解过flex-grow的具体用法后,这周,让我们一起来见一下flex-basis这个属性. flex-shrink 定义项目的缩小比例,默认值为1,注意前提是空间不足的情况下,项目缩 ...

  10. 杂谈:大容量(T级容量)的网盘的意义

    这两天,大容量的网盘的消息不断的推出.有百度的网盘推1T容量的:有腾讯的推10T容量的:有的还推不限容量的等等不一而足. 先看看大容量网盘的历史 早先是没有网盘这个概念的.能提供免费空间是电子邮箱 早 ...