说明:阅读本文之前,请先掌握本文前置知识: 跳表 核心原理 图解,以及ConcurrentSkipListMap - 秒懂

JUC 高并发工具类(3文章)与高并发容器类(N文章) :


1 ConcurrentSkipListSet简介

ConcurrentSkipListSet,是J.U.C新增的一个集合工具类,顾名思义,它是一种SET类型。

SET类型,在数学上称为“集合”,具有互异性、无序性的特点,也就是说SET中的任意两个元素均不相同(即不包含重复元素),且元素是无序的。

JDK提供的默认SET实现——HashSet,其实就是采用“组合”的方式——内部引用了一个HashMap对象,以此实现SET的功能。

ConcurrentSkipListSet与ConcurrentSkipListMap的关系,与SET与HashMap的关系类似,就是采用“组合”的方式: ConcurrentSkipListSet组合了一个ConcurrentSkipListMap,将元素作为 ConcurrentSkipListMap的key存放。

2 ConcurrentSkipListSet原理

2.1 ConcurrentSkipListSet的类继承图

我们来看下ConcurrentSkipListSet的类继承图:

2.2 内部结构

ConcurrentSkipListSet的数据结构,如下图所示:

说明:

(01) ConcurrentSkipListSet继承于AbstractSet。因此,它本质上是一个集合。

(02) ConcurrentSkipListSet实现了NavigableSet接口。因此,ConcurrentSkipListSet是一个有序的集合。

(03) ConcurrentSkipListSet是通过组合ConcurrentSkipListMap实现的。它包含一个ConcurrentNavigableMap对象m,而m对象实际上是ConcurrentNavigableMap的实现类ConcurrentSkipListMap的实例。ConcurrentSkipListMap中的元素是key-value键值对;而ConcurrentSkipListSet是集合,它只用到了ConcurrentSkipListMap中的key!

2.3 构造器

ConcurrentSkipListSet的实现非常简单,其内部引用了一个ConcurrentSkipListMap对象,所有API方法均委托ConcurrentSkipListMap对象完成:

  1. public class ConcurrentSkipListSet<E> extends AbstractSet<E>
  2. implements NavigableSet<E>, Cloneable, java.io.Serializable {
  3. /**
  4. * The underlying map. Uses Boolean.TRUE as value for each
  5. * element. This field is declared final for the sake of thread
  6. * safety, which entails some ugliness in clone().
  7. */
  8. private final ConcurrentNavigableMap<E, Object> m;
  9. public ConcurrentSkipListSet() {
  10. m = new ConcurrentSkipListMap<E, Object>();
  11. }
  12. public ConcurrentSkipListSet(Comparator<? super E> comparator) {
  13. m = new ConcurrentSkipListMap<E, Object>(comparator);
  14. }
  15. public ConcurrentSkipListSet(Collection<? extends E> c) {
  16. m = new ConcurrentSkipListMap<E, Object>();
  17. addAll(c);
  18. }
  19. public ConcurrentSkipListSet(SortedSet<E> s) {
  20. m = new ConcurrentSkipListMap<E, Object>(s.comparator());
  21. addAll(s);
  22. }
  23. ConcurrentSkipListSet(ConcurrentNavigableMap<E, Object> m) {
  24. this.m = m;
  25. }
  26. // ...
  27. }

从上述代码可以看出,ConcurrentSkipListSet在构造时创建了一个ConcurrentSkipListMap对象,并由字段m引用,所以其实ConcurrentSkipListSet就是一种跳表类型的数据结构,其平均增删改查的时间复杂度均为O(logn)。

2.4 核心方法

我们来看下ConcurrentSkipListSet是如何实现API方法的:


  1. public int size() {
  2. return m.size();
  3. }
  4. public boolean isEmpty() {
  5. return m.isEmpty();
  6. }
  7. public boolean contains(Object o) {
  8. return m.containsKey(o);
  9. }
  10. public boolean add(E e) {
  11. return m.putIfAbsent(e, Boolean.TRUE) == null;
  12. }
  13. public boolean remove(Object o) {
  14. return m.remove(o, Boolean.TRUE);
  15. }
  16. public void clear() {
  17. m.clear();
  18. }
  19. //...

从上述代码可以看出,所有操作均是委托ConcurrentSkipListMap对象完成的。重点看下add方法:

public boolean add(E e) {

​ return m.putIfAbsent(e, Boolean.TRUE) == null;

}

ConcurrentSkipListMap对键值对的要求是均不能为null,所以ConcurrentSkipListSet在插入元素的时候,用一个Boolean.TRUE对象(相当于一个值为true的Boolean型对象)作为value,同时putIfAbsent可以保证不会存在相同的Key。

所以,最终跳表中的所有Node结点的Key均不会相同,且值都是Boolean.True

3 ConcurrentSkipListSet适用场景

ConcurrentSkipListSet是线程安全的有序的集合,适用于高并发的场景。

ConcurrentSkipListSet和TreeSet

ConcurrentSkipListSet和TreeSet,它们虽然都是有序的集合。但是,第一,它们的线程安全机制不同,TreeSet是非线程安全的,而ConcurrentSkipListSet是线程安全的。第二,ConcurrentSkipListSet是通过ConcurrentSkipListMap实现的,而TreeSet是通过TreeMap实现的。

4 使用例子

  1. import java.util.*;
  2. import java.util.concurrent.*;
  3. /*
  4. * ConcurrentSkipListSet是“线程安全”的集合,而TreeSet是非线程安全的。
  5. *
  6. * 下面是“多个线程同时操作并且遍历集合set”的示例
  7. * (01) 当set是ConcurrentSkipListSet对象时,程序能正常运行。
  8. * (02) 当set是TreeSet对象时,程序会产生ConcurrentModificationException异常。
  9. *
  10. * @author skywang
  11. */
  12. public class ConcurrentSkipListSetDemo1 {
  13. // TODO: set是TreeSet对象时,程序会出错。
  14. //private static Set<String> set = new TreeSet<String>();
  15. private static Set<String> set = new ConcurrentSkipListSet<String>();
  16. public static void main(String[] args) {
  17. // 同时启动两个线程对set进行操作!
  18. new MyThread("a").start();
  19. new MyThread("b").start();
  20. }
  21. private static void printAll() {
  22. String value = null;
  23. Iterator iter = set.iterator();
  24. while(iter.hasNext()) {
  25. value = (String)iter.next();
  26. System.out.print(value+", ");
  27. }
  28. System.out.println();
  29. }
  30. private static class MyThread extends Thread {
  31. MyThread(String name) {
  32. super(name);
  33. }
  34. @Override
  35. public void run() {
  36. int i = 0;
  37. while (i++ < 10) {
  38. // “线程名” + "序号"
  39. String val = Thread.currentThread().getName() + (i%6);
  40. set.add(val);
  41. // 通过“Iterator”遍历set。
  42. printAll();
  43. }
  44. }
  45. }
  46. }

运行程序,结果如下:

  1. a1, b1,
  2. a1, a1, a2, b1,
  3. b1, a1, a2, a3, b1,
  4. a1, a2, a3, a1, a4, b1, b2,
  5. a2, a1, a2, a3, a4, a5, b1, b2,
  6. a3, a0, a4, a5, a1, b1, a2, b2,
  7. a3, a0, a4, a1, a5, a2, b1, a3, b2, a4, b3,
  8. a5, a0, b1, a1, b2, a2, b3,
  9. a3, a0, a4, a1, a5, a2, b1, a3, b2, a4, b3, a5, b4,
  10. b1, a0, b2, a1, b3, a2, b4,
  11. a3, a0, a4, a1, a5, a2, b1, a3, b2, a4, b3, a5, b4, b1, b5,
  12. b2, a0, a1, a2, a3, a4, a5, b3, b1, b4, b2, b5,
  13. b3, a0, b4, a1, b5,
  14. a2, a0, a3, a1, a4, a2, a5, a3, b0, a4, b1, a5, b2, b0, b3, b1, b4, b2, b5, b3,
  15. b4, a0, b5,
  16. a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5,
  17. a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5,
  18. a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5,
  19. a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5,

回到疯狂创客圈

疯狂创客圈 - Java高并发研习社群,为大家开启大厂之门

ConcurrentSkipListSet - 秒懂的更多相关文章

  1. CyclicBarrier 原理(秒懂)

    疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 面试必备 + 面试必备 [博客园总入口 ] 疯狂创客圈 经典图书 : <Sprin ...

  2. ConcurrentSkipListMap - 秒懂

    疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 面试必备 + 面试必备 [博客园总入口 ] 疯狂创客圈 经典图书 : <Sprin ...

  3. JUC并发包与容器类 - 面试题(一网打净,持续更新)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  4. 【JUC】JDK1.8源码分析之ConcurrentSkipListSet(八)

    一.前言 分析完了CopyOnWriteArraySet后,继续分析Set集合在JUC框架下的另一个集合,ConcurrentSkipListSet,ConcurrentSkipListSet一个基于 ...

  5. 30秒懂SQL中的join(2幅图+30秒)

    废话不多说,直接上图秒懂. t1表的结构与数据如下: t2表的结构与数据如下: inner join select * from t1 inner join t2 on t1.id = t2.id; ...

  6. Java多线程系列--“JUC集合”06之 ConcurrentSkipListSet

    概要 本章对Java.util.concurrent包中的ConcurrentSkipListSet类进行详细的介绍.内容包括:ConcurrentSkipListSet介绍ConcurrentSki ...

  7. 并发容器之ConcurrentSkipListSet

    概要 本章对Java.util.concurrent包中的ConcurrentSkipListSet类进行详细的介绍.内容包括:ConcurrentSkipListSet介绍ConcurrentSki ...

  8. 死磕 java集合之ConcurrentSkipListSet源码分析——Set大汇总

    问题 (1)ConcurrentSkipListSet的底层是ConcurrentSkipListMap吗? (2)ConcurrentSkipListSet是线程安全的吗? (3)Concurren ...

  9. 并发容器学习—ConcurrentSkipListMap与ConcurrentSkipListSet 原

    一.ConcurrentSkipListMap并发容器 1.ConcurrentSkipListMap的底层数据结构     要学习ConcurrentSkipListMap,首先要知道什么是跳表或跳 ...

随机推荐

  1. [面向对象之继承应用(在子类派生重用父类功能(super),继承实现原理(继承顺序、菱形问题、继承原理、Mixins机制),组合]

    [面向对象之继承应用(在子类派生重用父类功能(super),继承实现原理(继承顺序.菱形问题.继承原理.Mixins机制),组合] 继承应用 类与类之间的继承指的是什么'是'什么的关系(比如人类,猪类 ...

  2. xxl-job源码阅读二(服务端)

    1.源码入口 xxl-job-admin是一个简单的springboot工程,简单翻看源码,可以很快发现XxlJobAdminConfig入口. @Override public void after ...

  3. 解密华为云FusionInsight MRS新特性:一架构三湖

    摘要:华为云安全网关产品总监郭冕在"华为云TechWave云原生2.0专题日"上发表<华为云FusionInsight MRS,一个架构实现三种数据湖>的主题演讲,分享 ...

  4. golang:数据类型总结

    Go语言将数据类型分为四类:基础类型.复合类型.引用类型和接口类型. 基础数据类型包括: 基础类型: - 布尔型.整型.浮点型.复数型.字符型.字符串型.错误类型. 复合数据类型包括: - 指针.数组 ...

  5. 用源码搭建LNMP环境+部署WordPress

    首先要做的是就是关闭Centos7.4的防火墙及selinux #systemctl stop firewalld #systemctl disable firewalld #sed -ri 's/^ ...

  6. Linux 操作系统(三) 添加用户、切换用户、删除用户

    以下命令均已在 Kali Linux 验证. 1.添加用户 --1-- useradd -m username            //username 代表你所添加的用户名 --2-- passw ...

  7. Socket编程——(转载)

    我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠so ...

  8. python基础之错误、调试(异常处理)

    在程序运行过程中,总会遇到各种各样的错误. 有的错误是程序编写有问题造成的,比如本来应该输出整数结果输出了字符串,这种错误我们通常称之为bug,bug是必须修复的. 有的错误是用户输入造成的,比如让用 ...

  9. kylin优化的思想

    kylin的核心优势在于使用额外的空间存储预计算的结果,以换取查询时间的缩减. 所以我们要对额外的空间进行优化,并且在空间优化之后,cuboid无法完全命中时,对查询时间进行优化. 空间优化的思路就是 ...

  10. USB NCM介绍

    ​1 功能概述 USB NCM,属于USB-IF定义的CDC(Communication Device Class)下的一个子类:Network Control Model,用于Host和Device ...