本文首发于一世流云专栏: https://segmentfault.com/blog...
ConcurrentSkipListSet,是JDK1.6时J.U.C新增的一个集合工具类,顾名思义,它是一种SET类型。java
SET类型,在数学上称为“集合”,具备互异性、无序性的特色,也就是说SET中的任意两个元素均不相同(即不包含重复元素),且元素是无序的。
是否是感受和HashMap有点相似?HashMap中的Key也是不能重复,且是无序的。segmentfault
事实上,JDK提供的默认SET实现——HashSet
,其实就是采用“组合”的方式——内部引用了一个HashMap对象,以此实现SET的功能。数据结构
咱们来看下ConcurrentSkipListSet的类继承图:多线程
能够看到,ConcurrentSkipListSet实现了NavigableSet
接口,在Java多线程进阶(二五)—— J.U.C之collections框架:ConcurrentSkipListMap中,咱们提到过ConcurrentSkipListMap实现了NavigableMap
接口,以提供和排序相关的功能,维持元素的有序性,因此ConcurrentSkipListSet就是一种为并发环境设计的有序SET工具类。并发
NavigableSet的功能和 NavigableMap几乎是彻底同样的,提供了根据指定Key返回最接近项、按升序/降序返回全部键的视图等功能。惟一的区别是NavigableSet针对的仅仅是键值,NavigableMap针对键值对进行操做。
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)
。工具
咱们来看下ConcurrentSkipListSet是如何实现API方法的:this
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
方法:spa
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
。