ConcurrentSkipList在 C# 中 **不是内置类型**,.NET 标准库(包括 .NET 5/6/7/8/9)至今(2025年12月)**没有提供
ConcurrentSkipListMap或
ConcurrentSkipListSet的等价实现**。
为什么 C# 没有内置 ConcurrentSkipList?
Java 的
ConcurrentSkipListMap/Set是 J.U.C 包为高并发有序场景量身定制的无锁跳表结构,而 .NET 的并发集合设计路径不同: .NET 优先强化了
ConcurrentDictionary<k></k>(哈希分段锁)和
ConcurrentQueue<t></t>等无序/队列类,但对「线程安全 + 有序 + 高并发」这一组合,官方未落地跳表实现
SortedSet<t></t>和
SortedList<k></k>是有序的,但**完全不支持并发修改**——多线程写入会直接抛
InvalidOperationException或产生未定义行为 虽然 .NET 6+ 引入了
System.Collections.Generic.PriorityQueue<telement></telement>,但它不支持范围查询、导航操作(如
ceiling、
floor),也不满足「并发 + 排序 + Navigable」需求
C# 中替代 ConcurrentSkipListSet 的实际方案
若你正需要类似 Java 中
ConcurrentSkipListSet的能力(即:线程安全、自动排序、支持子集/前驱/后继查询),目前只有两条可行路径: 用
ConcurrentDictionary<t></t>+ 外部锁 +
SortedSet<t></t>包装:手动加
lock或
ReaderWriterLockSlim,牺牲并发度换正确性;适用于读多写少、QPS 不高的场景 引入第三方库:例如
ConcurrentCollections(开源 NuGet 包),它提供了
ConcurrentCollections和
ConcurrentSkipListSet<t></t>,底层基于跳表 + CAS,API 风格贴近 Java,已在生产环境验证
示例(使用第三方库):
var set = new ConcurrentSkipListSet<int>(); set.Add(42); set.Add(15); set.Add(99); // O(log n) 并发安全的导航操作 int? ceiling = set.Ceiling(50); // → 99 int? floor = set.Floor(50); // → 42
误用 SortedSet 做并发读写的典型错误
很多开发者尝试直接把
ConcurrentSkipListMap<k></k>放进多线程环境,结果出现诡异行为: 现象:遍历时抛
SortedSet<t></t>,或返回重复/丢失元素 原因:
InvalidOperationException: Collection was modified内部是红黑树,所有结构变更(
SortedSet<t></t>/
Add)都会重平衡,且无任何同步机制 注意:
Remove不是快照式迭代器 —— 它在遍历中遇到并发修改会立即失败,不像 Java 的
GetEnumerator()那样提供弱一致性遍历
跳表的局部更新特性决定了它天然适合高并发有序场景,而 C# 官方尚未填补这个空白。如果你的业务强依赖
ConcurrentSkipListSet、
subSet、
headSet或低延迟范围扫描,别硬套
tailSet+ 排序临时列表 —— 那会退化成 O(n log n),且无法保证原子性。要么接受第三方库,要么自己基于
ConcurrentDictionary和链表手撸跳表(不推荐)。
