Java多线程进阶(25)—— J.U.C之collections框架:ConcurrentSkipListSet

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

一、ConcurrentSkipListSet简介

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

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

是不是感觉和HashMap有点类似?HashMap中的Key也是不能重复,且是无序的。

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

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

可以看到,ConcurrentSkipListSet实现了NavigableSet接口,在Java多线程进阶(24)—— J.U.C之collections框架:ConcurrentSkipListMap中,我们提到过ConcurrentSkipListMap实现了NavigableMap接口,以提供和排序相关的功能,维持元素的有序性,所以 ConcurrentSkipListSet 就是一种为并发环境设计的有序SET工具类。

NavigableSet 的功能和 NavigableMap 几乎是完全一样的,提供了根据指定Key返回最接近项、按升序/降序返回所有键的视图等功能。唯一的区别是NavigableSet针对的仅仅是键值,NavigableMap针对键值对进行操作。

二、ConcurrentSkipListSet原理

2.1 内部结构

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

    public class ConcurrentSkipListSet<E> extends AbstractSet<E>
        implements NavigableSet<E>, Cloneable, java.io.Serializable {
    
        /**
         * The underlying map. Uses Boolean.TRUE as value for each
         * element.  This field is declared final for the sake of thread
         * safety, which entails some ugliness in clone().
         */
        private final ConcurrentNavigableMap<E, Object> m;
    
        public ConcurrentSkipListSet() {
            m = new ConcurrentSkipListMap<E, Object>();
        }
    
        public ConcurrentSkipListSet(Comparator<? super E> comparator) {
            m = new ConcurrentSkipListMap<E, Object>(comparator);
        }
    
        public ConcurrentSkipListSet(Collection<? extends E> c) {
            m = new ConcurrentSkipListMap<E, Object>();
            addAll(c);
        }
    
        public ConcurrentSkipListSet(SortedSet<E> s) {
            m = new ConcurrentSkipListMap<E, Object>(s.comparator());
            addAll(s);
        }
    
        ConcurrentSkipListSet(ConcurrentNavigableMap<E, Object> m) {
            this.m = m;
        }
    
        // ...
    }

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

2.2 核心方法

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

    public int size() {
        return m.size();
    }
    
    public boolean isEmpty() {
        return m.isEmpty();
    }
    
    public boolean contains(Object o) {
        return m.containsKey(o);
    }
    
    
    public boolean add(E e) {
        return m.putIfAbsent(e, Boolean.TRUE) == null;
    }
    
    public boolean remove(Object o) {
        return m.remove(o, Boolean.TRUE);
    }
    
    public void clear() {
        m.clear();
    }
    //...

从上述代码可以看出,所有操作均是委托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

  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值