
ConcurrentSkipListMap 是什么:不是红黑树,也不是 HashMap 的线程安全版
它是一个线程安全、按键有序的 Map,底层用跳表(Skip List)实现,不是红黑树,也不是对 TreeMap 或 HashMap 加锁改造出来的。这意味着它天然支持高并发读写 + 有序遍历,且无需外部同步。
-
TreeMap是单线程安全的,多线程下必须手动加锁或包装成Collections.synchronizedSortedMap(),但会严重串行化操作 -
ConcurrentHashMap虽然并发性能好,但完全无序——你调用firstKey()或想取“评分前 10 的商品”,它根本不支持 -
ConcurrentSkipListMap同时解决了“有序”和“并发”两个硬需求,代价是平均时间复杂度为O(log n)(非O(1)),但稳定、可预测
什么时候该用它:别在日志计数或缓存场景硬套
它适合「既要实时并发更新,又要按 key 做范围查询或顺序遍历」的场景。用错地方反而拖慢系统。
- ✅ 合适:实时排行榜(按分数/时间戳排序)、延迟任务调度队列(key = 执行时间)、分布式 ID 分段管理(key = 段起始值)
- ❌ 不合适:纯缓存(如用户 session 存储)、高频单 key 查找且不要求顺序(这时
ConcurrentHashMap更快)、键无自然序或需自定义 hash 行为(它强制要求 key 可比较) - ⚠️ 注意:构造时若传入
null键或值,会直接抛NullPointerException;即使 key 实现了Comparable,若比较逻辑返回0但对象不等(违反 equals 合约),行为未定义
怎么初始化和选构造器:自然序 vs 自定义 Comparator 很关键
构造方式直接影响 key 的排序逻辑和空值容忍度,选错会导致 ClassCastException 或运行时异常。
- 用自然序:
new ConcurrentSkipListMap()→ 要求 key 类型必须实现Comparable,比如Integer、String、LocalDateTime - 用自定义序:
new ConcurrentSkipListMap(Comparator.reverseOrder())→ 可反转顺序,也可用于不可比类型(如自定义类),但必须确保 comparator 不接受null,否则put(null, v)会炸 - 从已有 map 构建:
new ConcurrentSkipListMap(otherMap)→ 仅复制映射关系,排序规则沿用otherMap的 comparator 或 natural order;若otherMap是HashMap,会报ClassCastException(因它没实现SortedMap)
常见误用坑:subMap / headMap 返回的是动态视图,不是副本
像 subMap(from, to)、headMap(to) 这些方法返回的不是新 Map,而是原 Map 的实时视图——原 Map 改了,视图立刻反映变化,反之亦然。这点和 TreeMap 一致,但新手常以为是快照。
立即学习“Java免费学习笔记(深入)”;
- 如果需要固定快照,得显式拷贝:
new ConcurrentSkipListMap(map.subMap(k1, k2)) - 视图本身也线程安全,但多个线程同时通过视图和原 map 修改重叠 key 区间,不会出错,只是结果取决于执行时序
- 用
descendingMap()获取降序视图后,再调用其put(),仍会插入到原结构中,只是遍历顺序变了——别以为它开辟了新空间
TreeMap 略高,且首次扩容无预热,小数据量时未必比加锁的 TreeMap 快。别只看文档说“高并发”,先压测你的典型读写比和 key 分布。










