ConcurrentSkipListMap 用跳表替代红黑树,核心是更适合并发:锁粒度小、读无锁、无再平衡阻塞、实现简单、区间查询高效、接受可控概率代价换取工程稳定性。

ConcurrentSkipListMap 用跳表替代红黑树,核心不是“谁更快”,而是“谁更适合并发”。它解决的不是单线程下的理论最优,而是多线程场景中可落地、易维护、冲突少、扩展稳的实际问题。
并发控制天然友好:局部修改不牵连全局
跳表插入或删除一个节点,只影响该节点所在路径上 O(log n) 层的前后指针,每层可独立用 CAS 更新;而红黑树一次插入可能触发旋转+染色,波及父、叔、祖父等多个节点,必须加锁保护整条路径甚至更大范围。这意味着:
- 跳表写操作锁粒度小,线程间冲突概率低
- 读操作完全无锁,靠 volatile + CAS 保证可见性
- 没有“再平衡阻塞期”,吞吐量随线程数增长更平缓
实现与维护成本显著更低
跳表逻辑清晰:每层是带前向指针的有序链表,新节点层数由随机数决定(通常 P=0.5),插入只需在各层找到前驱并 CAS 链接。相比之下:
- 红黑树需处理 4 类旋转 + 多种颜色翻转组合,边界条件复杂
- 并发环境下模拟树结构的无锁更新至今没有高效通用解法
- 跳表代码量约为红黑树的 1/3,调试、验证、长期维护压力小得多
区间查询更直接高效
subMap、headMap、tailMap 等视图操作本质是范围切片。跳表从起始键定位后,可沿最底层链表顺序遍历,时间复杂度为 O(log n + k),k 是结果数量;红黑树虽也能做到 O(log n + k),但需先找起点,再中序遍历,缓存局部性差,且并发时遍历过程容易受结构变更干扰。
- 跳表的链表结构天然支持稳定顺序扫描
- 视图操作不复制数据,直接复用底层跳表指针,内存友好
- 注意:clear() 会清空整个原始 map,不是仅清子视图——这是高频误用点
接受可控的概率代价,换取确定的工程收益
跳表最坏情况是 O(n),但概率随层数指数衰减(如 32 层跳表,O(n) 概率低于 10⁻⁹)。实际系统中,这种统计保障足够可靠;而红黑树虽有严格 O(log n) 上界,却在并发下因锁竞争导致延迟毛刺明显、尾部延迟不可控。
- 现代硬件更倾向“平均快+抖动小”,而非“最坏稳+常数大”
- 内存成本略高(多层索引)已不是瓶颈,CPU 时间和开发效率才是关键
- Redis ZSet 和 ConcurrentSkipListMap 不约而同选跳表,印证了这一权衡的普适性










