JDK 8 ConcurrentSkipListSet 源码详解(详细注释版)
1. 类定义和基本属性
public class ConcurrentSkipListSet<E>
extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable {
// 序列化版本号
private static final long serialVersionUID = -2479143111061671589L;
/**
* 底层使用ConcurrentSkipListMap实现
* 利用Map的键来存储Set的元素
* 值使用统一的虚拟对象PRESENT
*/
private final ConcurrentNavigableMap<E,Object> m;
/**
* 用于映射键值的虚拟值对象
* 所有元素都映射到这个相同的对象
* 节省内存空间,避免为每个元素创建值对象
*/
private static final Object PRESENT = new Object();
/**
* 默认构造方法
* 创建一个空的ConcurrentSkipListSet
* 使用元素的自然排序
*
* 初始化过程:
* 1. 创建ConcurrentSkipListMap实例
* 2. 使用自然排序比较器
* 3. 为空Set做好准备
*/
public ConcurrentSkipListSet() {
m = new ConcurrentSkipListMap<E,Object>();
}
/**
* 使用指定比较器的构造方法
* @param comparator 用于排序的比较器
*
* 比较器说明:
* - 如果comparator为null,使用自然排序
* - 否则使用指定的比较器进行排序
* - 比较器必须保持一致性
* - 元素类型必须与比较器兼容
*/
public ConcurrentSkipListSet(Comparator<? super E> comparator) {
m = new ConcurrentSkipListMap<E,Object>(comparator);
}
/**
* 从Collection构造ConcurrentSkipListSet
* @param c 包含初始元素的集合
*
* 构造过程:
* 1. 使用自然排序创建底层Map
* 2. 将集合中的所有元素添加到Set中
* 3. 保持元素的唯一性和有序性
*
* 注意事项:
* - 集合中的元素必须可比较
* - 重复元素会被自动去除
* - 元素按照排序规则排列
*/
public ConcurrentSkipListSet(Collection<? extends E> c) {
m = new ConcurrentSkipListMap<E,Object>();
addAll(c);
}
/**
* 从SortedSet构造ConcurrentSkipListSet
* @param s 包含初始元素的有序集合
*
* 构造过程:
* 1. 使用s的比较器创建底层Map
* 2. 将有序集合中的元素添加到Set中
* 3. 保持原有的排序顺序
* 4. 去除可能的重复元素
*
* 优势:
* - 保持原有的排序特性
* - 避免重新排序的开销
* - 提高构造效率
*/
public ConcurrentSkipListSet(SortedSet<E> s) {
m = new ConcurrentSkipListMap<E,Object>(s.comparator());
addAll(s);
}
/**
* 私有构造方法(包私有)
* 用于内部创建,直接指定底层Map
* @param m 底层的ConcurrentNavigableMap
*
* 设计目的:
* - 支持子集视图的创建
* - 避免重复创建Map实例
* - 保持与原Set的关联关系
*/
ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) {
this.m = m;
}
2. 核心集合操作方法(详细注释)
/**
* 添加元素到Set中
* @param e 要添加的元素
* @return 如果元素不存在则添加成功返回true,否则返回false
*
* 添加过程:
* 1. 调用底层Map的putIfAbsent方法
* 2. 如果元素不存在,添加成功返回true
* 3. 如果元素已存在,添加失败返回false
* 4. 保持Set的唯一性约束
*
* 时间复杂度:平均O(log n)
* 线程安全性:完全线程安全
*/
public boolean add(E e) {
return m.putIfAbsent(e, PRESENT) == null;
}
/**
* 从Set中移除指定元素
* @param o 要移除的元素
* @return 如果元素存在并成功移除返回true,否则返回false
*
* 移除过程:
* 1. 调用底层Map的remove方法
* 2. 如果元素存在,移除成功返回true
* 3. 如果元素不存在,移除失败返回false
* 4. 保持Set的一致性
*
* 时间复杂度:平均O(log n)
* 线程安全性:完全线程安全
*/
public boolean remove(Object o) {
return m.remove(o) == PRESENT;
}
/**
* 判断Set是否包含指定元素
* @param o 要检查的元素
* @return 如果包含返回true,否则返回false
*
* 查找过程:
* 1. 调用底层Map的containsKey方法
* 2. 利用跳表的快速查找特性
* 3. 保持O(log n)的查找性能
*
* 时间复杂度:平均O(log n)
* 线程安全性:完全线程安全
*/
public boolean contains(Object o) {
return m.containsKey(o);
}
/**
* 返回Set中元素的个数
* @return 元素个数
*
* 计数特点:
* 1. 调用底层Map的size方法
* 2. 在高并发环境下可能返回估算值
* 3. 保证不会抛出异常
* 4. 性能较高,无需遍历
*
* 时间复杂度:O(1)
* 注意:在并发环境下可能不是精确值
*/
public int size() {
return m.size();
}
/**
* 判断Set是否为空
* @return 如果为空返回true,否则返回false
*
* 判断过程:
* 1. 调用底层Map的isEmpty方法
* 2. 直接检查Map的大小
* 3. 性能优异,时间复杂度O(1)
*
* 时间复杂度:O(1)
* 线程安全性:完全线程安全
*/
public boolean isEmpty() {
return m.isEmpty();
}
/**
* 清空Set中的所有元素
*
* 清空过程:
* 1. 调用底层Map的clear方法
* 2. 原子性地移除所有元素
* 3. 释放相关资源
* 4. 保持线程安全性
*
* 时间复杂度:O(n)
* 线程安全性:完全线程安全
*/
public void clear() {
m.clear();
}
3. 迭代器相关方法(详细注释)
/**
* 返回Set的迭代器
* @return 按升序排列的迭代器
*
* 迭代器特点:
* 1. 弱一致性:反映创建时的状态快照
* 2. 不会抛出ConcurrentModificationException
* 3. 线程安全:可以在并发环境下使用
* 4. 有序性:按照元素的排序规则遍历
* 5. 效率高:利用底层Map的迭代器实现
*
* 使用场景:
* - 遍历所有元素
* - 顺序处理元素
* - 在并发环境中的安全遍历
*/
public Iterator<E> iterator() {
return m.navigableKeySet().iterator();
}
/**
* 返回Set的降序迭代器
* @return 按降序排列的迭代器
*
* 降序迭代器特点:
* 1. 从最大元素开始遍历
* 2. 按照排序规则的逆序遍历
* 3. 同样具有弱一致性
* 4. 线程安全且高效
*
* 使用场景:
* - 反向遍历元素
* - 获取最大元素及以下的元素
* - 实现降序处理逻辑
*/
public Iterator<E> descendingIterator() {
return m.descendingKeySet().iterator();
}
/**
* 将Set转换为数组
* @return 包含所有元素的数组
*
* 转换特点:
* 1. 保持元素的排序顺序
* 2. 线程安全的操作
* 3. 返回新的数组对象
* 4. 不影响原Set的状态
*
* 实现方式:
* 1. 调用底层Map的keySet().toArray()
* 2. 利用Map的有序特性保证数组顺序
*/
public Object[] toArray() {
return m.keySet().toArray();
}
/**
* 将Set转换为指定类型的数组
* @param a 指定类型的数组
* @return 转换后的数组
* @throws ArrayStoreException 如果数组类型不兼容
* @throws NullPointerException 如果a为null
*
* 类型转换特点:
* 1. 保持元素的排序顺序
* 2. 类型安全的转换
* 3. 可能创建新的数组实例
* 4. 保持线程安全性
*/
public <T> T[] toArray(T[] a) {
return m.keySet().toArray(a);
}
4. 导航操作方法(详细注释)
/**
* 返回用于排序的比较器
* @return 比较器,如果使用自然排序则返回null
*
* 比较器特点:
* 1. 直接返回底层Map的比较器
* 2. 保持一致性
* 3. 线程安全
* 4. O(1)时间复杂度
*/
public Comparator<? super E> comparator() {
return m.comparator();
}
/**
* 返回第一个(最小)元素
* @return 第一个元素
* @throws NoSuchElementException 如果Set为空
*
* 查找过程:
* 1. 调用底层Map的firstKey方法
* 2. 利用跳表的特性快速定位
* 3. 时间复杂度O(log n)
*
* 异常处理:
* - 当Set为空时抛出NoSuchElementException
* - 保证操作的原子性
*/
public E first() {
return m.firstKey();
}
/**
* 返回最后一个(最大)元素
* @return 最后一个元素
* @throws NoSuchElementException 如果Set为空
*
* 查找过程:
* 1. 调用底层Map的lastKey方法
* 2. 利用跳表的特性快速定位
* 3. 时间复杂度O(log n)
*
* 使用场景:
* - 获取最大元素
* - 实现边界检查
* - 优化范围查询
*/
public E last() {
return m.lastKey();
}
/**
* 返回小于等于指定元素的最大元素
* @param e 指定元素
* @return 小于等于e的最大元素,如果不存在则返回null
*
* Floor操作特点:
* 1. 利用底层Map的floorKey方法
* 2. 保持O(log n)的时间复杂度
* 3. 线程安全的操作
* 4. 支持null返回值
*
* 应用场景:
* - 范围查询
* - 边界查找
* - 实现floor函数
*/
public E floor(E e) {
return m.floorKey(e);
}
/**
* 返回大于等于指定元素的最小元素
* @param e 指定元素
* @return 大于等于e的最小元素,如果不存在则返回null
*
* Ceiling操作特点:
* 1. 利用底层Map的ceilingKey方法
* 2. 保持O(log n)的时间复杂度
* 3. 线程安全的操作
* 4. 支持null返回值
*
* 应用场景:
* - 范围查询
* - 边界查找
* - 实现ceiling函数
*/
public E ceiling(E e) {
return m.ceilingKey(e);
}
/**
* 返回小于指定元素的最大元素
* @param e 指定元素
* @return 小于e的最大元素,如果不存在则返回null
*
* Lower操作特点:
* 1. 利用底层Map的lowerKey方法
* 2. 保持O(log n)的时间复杂度
* 3. 线程安全的操作
* 4. 不包含等于的情况
*
* 应用场景:
* - 严格小于的查找
* - 前驱元素查找
* - 实现lower函数
*/
public E lower(E e) {
return m.lowerKey(e);
}
/**
* 返回大于指定元素的最小元素
* @param e 指定元素
* @return 大于e的最小元素,如果不存在则返回null
*
* Higher操作特点:
* 1. 利用底层Map的higherKey方法
* 2. 保持O(log n)的时间复杂度
* 3. 线程安全的操作
* 4. 不包含等于的情况
*
* 应用场景:
* - 严格大于的查找
* - 后继元素查找
* - 实现higher函数
*/
public E higher(E e) {
return m.higherKey(e);
}
5. 元素提取和删除方法(详细注释)
/**
* 检索并移除第一个(最小)元素
* @return 第一个元素
* @throws NoSuchElementException 如果Set为空
*
* Poll操作特点:
* 1. 原子性操作:查找和删除同时进行
* 2. 利用底层Map的pollFirstEntry方法
* 3. 时间复杂度O(log n)
* 4. 线程安全
*
* 使用场景:
* - 优先队列实现
* - 获取并移除最小元素
* - 实现poll语义
*/
public E pollFirst() {
Map.Entry<E,Object> e = m.pollFirstEntry();
return (e == null) ? null : e.getKey();
}
/**
* 检索并移除最后一个(最大)元素
* @return 最后一个元素
* @throws NoSuchElementException 如果Set为空
*
* Poll操作特点:
* 1. 原子性操作:查找和删除同时进行
* 2. 利用底层Map的pollLastEntry方法
* 3. 时间复杂度O(log n)
* 4. 线程安全
*
* 使用场景:
* - 获取并移除最大元素
* - 实现降序poll语义
* - 双端队列操作
*/
public E pollLast() {
Map.Entry<E,Object> e = m.pollLastEntry();
return (e == null) ? null : e.getKey();
}
6. 范围操作方法(详细注释)
/**
* 返回此set的部分视图,元素范围从fromElement到toElement
* @param fromElement 起始元素(包含)
* @param toElement 结束元素(不包含)
* @return 指定范围的子集
*
* 子集特点:
* 1. 视图语义:与原Set共享数据
* 2. 动态更新:原Set的修改会反映到子集中
* 3. 边界检查:自动处理边界条件
* 4. 线程安全:继承原Set的线程安全性
*
* 使用场景:
* - 范围查询
* - 数据分片
* - 局部操作
*/
public NavigableSet<E> subSet(E fromElement,
boolean fromInclusive,
E toElement,
boolean toInclusive) {
return new ConcurrentSkipListSet<E>
(m.subMap(fromElement, fromInclusive, toElement, toInclusive));
}
/**
* 返回此set的部分视图,元素小于toElement
* @param toElement 结束元素(不包含)
* @param inclusive 是否包含结束元素
* @return 指定范围的头部集
*
* 头部集特点:
* 1. 从最小元素开始
* 2. 到指定元素结束
* 3. 支持包含/不包含边界
* 4. 保持有序性
*/
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
}
/**
* 返回此set的部分视图,元素大于等于fromElement
* @param fromElement 起始元素(包含)
* @param inclusive 是否包含起始元素
* @return 指定范围的尾部集
*
* 尾部集特点:
* 1. 从指定元素开始
* 2. 到最大元素结束
* 3. 支持包含/不包含边界
* 4. 保持有序性
*/
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
}
/**
* 返回此set的部分视图,元素范围从fromElement到toElement
* @param fromElement 起始元素(包含)
* @param toElement 结束元素(不包含)
* @return 指定范围的有序子集
*/
public SortedSet<E> subSet(E fromElement, E toElement) {
return subSet(fromElement, true, toElement, false);
}
/**
* 返回此set的部分视图,元素小于toElement
* @param toElement 结束元素(不包含)
* @return 指定范围的有序头部集
*/
public SortedSet<E> headSet(E toElement) {
return headSet(toElement, false);
}
/**
* 返回此set的部分视图,元素大于等于fromElement
* @param fromElement 起始元素(包含)
* @return 指定范围的有序尾部集
*/
public SortedSet<E> tailSet(E fromElement) {
return tailSet(fromElement, true);
}
7. 克隆方法(详细注释)
/**
* 克隆ConcurrentSkipListSet
* @return 克隆后的ConcurrentSkipListSet
*
* 克隆特点:
* 1. 浅克隆:只克隆Set结构,不克隆元素
* 2. 独立状态:新Set有自己的底层Map
* 3. 相同元素:包含相同的元素引用
* 4. 相同排序:保持相同的排序规则
* 5. 线程安全:克隆过程线程安全
*
* 克隆过程:
* 1. 创建新的ConcurrentSkipListSet实例
* 2. 克隆底层的ConcurrentNavigableMap
* 3. 保持原有的排序和元素
*/
public Object clone() {
try {
@SuppressWarnings("unchecked")
ConcurrentSkipListSet<E> clone =
(ConcurrentSkipListSet<E>) super.clone();
clone.m = new ConcurrentSkipListMap<E,Object>(m);
return clone;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
8. Spliterator(Java 8新增)
/**
* 返回Spliterator,用于并行处理
* @return Spliterator
*
* Spliterator特点:
* 1. 支持并行遍历
* 2. 有序性:保持元素的排序顺序
* 3. 线程安全:可以在并发环境下使用
* 4. 高效性:优化的分割算法
*
* 并行处理优势:
* - 提高大数据集的处理效率
* - 充分利用多核CPU
* - 减少处理时间
*/
public Spliterator<E> spliterator() {
return m.keySet().spliterator();
}
9. ConcurrentSkipListSet 的特点分析
核心设计理念:
/**
* ConcurrentSkipListSet的核心设计思想:
*
* 1. 委托模式:
* - 基于ConcurrentSkipListMap实现
* - 利用Map的键存储Set元素
* - 值使用统一的虚拟对象
* - 简化实现,复用成熟代码
*
* 2. 有序性保证:
* - 元素按照自然顺序或比较器排序
* - 支持导航操作
* - 提供有序的迭代器
* - 保持Set的唯一性约束
*
* 3. 线程安全性:
* - 继承底层Map的线程安全性
* - 所有操作都是原子的
* - 支持高并发读写
* - 无锁设计(通过底层Map实现)
*
* 4. 高效性:
* - 平均O(log n)的操作性能
* - 支持范围查询
* - 优化的内存使用
* - 良好的并发性能
*
* 5. 功能完整性:
* - 完整的Set操作
* - 丰富的导航功能
* - 灵活的范围操作
* - 支持子集视图
*
* 适用场景:
* - 需要有序Set的高并发场景
* - 频繁进行范围查询的场景
* - 需要导航操作的场景
* - 要求线程安全的有序集合
*/
性能特征分析:
/**
* ConcurrentSkipListSet的性能特征:
*
* 时间复杂度:
* - add(e): O(log n) 平均情况
* - remove(o): O(log n) 平均情况
* - contains(o): O(log n) 平均情况
* - size(): O(1) 平均情况
* - first()/last(): O(log n) 平均情况
* - floor(e)/ceiling(e): O(log n) 平均情况
* - lower(e)/higher(e): O(log n) 平均情况
* - pollFirst()/pollLast(): O(log n) 平均情况
*
* 空间复杂度:
* - O(n) 基本存储空间
* - 额外的索引节点开销(跳表特性)
* - 每个元素一个统一的PRESENT对象
* - 子集视图的额外开销
*
* 并发特性:
* - 完全线程安全
* - 无锁设计(通过底层Map实现)
* - 支持高并发读写
* - 弱一致性:读操作可能看不到最新的写操作
* - 不会抛出ConcurrentModificationException
*
* 内存使用:
* - 动态分配,按需扩展
* - 共享PRESENT对象节省内存
* - 及时GC,避免内存泄漏
* - 子集视图为视图语义,不复制数据
*
* 适用性:
* - 读操作频繁:性能优秀
* - 写操作频繁:性能良好
* - 范围查询:性能优秀
* - 有序遍历:性能优秀
*/
10. 使用示例和最佳实践
/**
* 使用示例:
*
* // 基本使用
* ConcurrentSkipListSet<String> set = new ConcurrentSkipListSet<>();
*
* // 添加元素
* set.add("apple");
* set.add("banana");
* set.add("cherry");
* set.add("apple"); // 重复元素,不会添加
*
* System.out.println("Set size: " + set.size()); // 输出: 3
* System.out.println("Contains apple: " + set.contains("apple")); // 输出: true
*
* // 导航操作
* String first = set.first(); // "apple"
* String last = set.last(); // "cherry"
* String floor = set.floor("blueberry"); // "banana"
* String ceiling = set.ceiling("blueberry"); // "cherry"
*
* // 范围操作
* NavigableSet<String> subSet = set.subSet("apple", true, "cherry", false);
* System.out.println("SubSet: " + subSet); // [apple, banana]
*
* // 迭代器使用
* System.out.println("Forward iteration:");
* for (String element : set) {
* System.out.println(element);
* }
*
* System.out.println("Backward iteration:");
* Iterator<String> descendingIt = set.descendingIterator();
* while (descendingIt.hasNext()) {
* System.out.println(descendingIt.next());
* }
*
* // 并发使用示例
* ExecutorService executor = Executors.newFixedThreadPool(10);
*
* // 并发添加
* for (int i = 0; i < 10; i++) {
* final int threadId = i;
* executor.submit(() -> {
* for (int j = 0; j < 1000; j++) {
* set.add("thread" + threadId + "_item" + j);
* }
* });
* }
*
* // 并发查询
* for (int i = 0; i < 10; i++) {
* executor.submit(() -> {
* for (int j = 0; j < 1000; j++) {
* boolean contains = set.contains("someElement");
* // 处理结果
* }
* });
* }
*
* 最佳实践:
*
* 1. 合理选择元素类型:
* // 元素应该实现Comparable接口或提供Comparator
* ConcurrentSkipListSet<Integer> numberSet = new ConcurrentSkipListSet<>();
*
* // 或者使用自定义比较器
* Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
* ConcurrentSkipListSet<String> stringSet =
* new ConcurrentSkipListSet<>(comparator);
*
* 2. 避免null元素:
* // ConcurrentSkipListSet不允许null元素
* try {
* set.add(null); // 抛出NullPointerException
* } catch (NullPointerException e) {
* System.out.println("Null elements are not allowed");
* }
*
* 3. 正确使用导航操作:
* // 利用导航操作提高查询效率
* String lower = set.lower("target");
* String higher = set.higher("target");
* if (lower != null) {
* System.out.println("Lower element: " + lower);
* }
* if (higher != null) {
* System.out.println("Higher element: " + higher);
* }
*
* 4. 合理使用范围操作:
* // 创建范围视图进行局部操作
* NavigableSet<String> range = set.headSet("m");
* System.out.println("Elements less than 'm': " + range.size());
*
* // 范围视图与原Set共享数据
* range.add("newElement"); // 也会添加到原Set中
*
* 5. 正确处理poll操作:
* // poll操作会同时检索和移除元素
* String firstElement = set.pollFirst();
* if (firstElement != null) {
* System.out.println("Polled element: " + firstElement);
* }
*
* 6. 监控Set状态:
* // 定期检查Set的大小和状态
* int size = set.size();
* boolean isEmpty = set.isEmpty();
* System.out.println("Set size: " + size + ", Is empty: " + isEmpty);
*
* // 注意:在高并发环境下size()可能是估算值
*
* 7. 使用子集视图:
* // 创建子集视图进行局部操作
* SortedSet<String> subset = set.subSet("a", "z");
* System.out.println("Subset size: " + subset.size());
*
* // 子集操作会反映到原Set中
* subset.add("newElement");
* System.out.println("Original set size: " + set.size());
*
* 8. 注意内存使用:
* // 大量数据时注意内存使用
* if (set.size() > 100000) {
* System.out.println("Large set size, consider memory usage");
* }
*
* 9. 正确使用迭代器:
* // 迭代器是弱一致性的
* Iterator<String> it = set.iterator();
* while (it.hasNext()) {
*