ConcurrentSkipListMap是高并发下支持排序的线程安全Map优选,基于跳跃表实现非阻塞的插入、删除和查找操作,提供O(log n)平均时间复杂度,相比synchronized TreeMap提升吞吐量。它实现NavigableMap接口,支持有序访问如firstEntry、subMap等范围查询,适用于任务调度、优先级队列等场景;使用时需注意键必须可比较,不支持null键值,迭代器为弱一致性,推荐结合putIfAbsent等原子操作避免竞态条件,适合读写混合且需自然排序的高并发环境。

在高并发场景下,如果需要一个支持排序的线程安全Map,ConcurrentSkipListMap 是比 TreeMap 或 Collections.synchronizedSortedMap 更优的选择。它基于跳跃表(SkipList)实现,提供非阻塞的并发插入、删除和查找操作,同时保持键的自然顺序或自定义排序。
1. ConcurrentSkipListMap 的基本使用
ConcurrentSkipListMap 实现了 NavigableMap 接口,支持有序访问,如获取小于/大于某个键的子集、获取第一个或最后一个条目等。
创建并使用示例:
ConcurrentSkipListMapmap = new ConcurrentSkipListMap<>(); map.put(3, "Three"); map.put(1, "One"); map.put(4, "Four"); // 输出按 key 升序排列 System.out.println(map); // {1=One, 3=Three, 4=Four}
支持自定义比较器:
立即学习“Java免费学习笔记(深入)”;
ConcurrentSkipListMapreverseMap = new ConcurrentSkipListMap<>(Collections.reverseOrder()); reverseMap.put("apple", 1); reverseMap.put("banana", 2); System.out.println(reverseMap); // {banana=2, apple=1}
2. 高并发下的优势与性能特点
与 TreeMap 相比,ConcurrentSkipListMap 在多线程环境下无需外部同步即可安全操作,其内部采用无锁算法(CAS)实现高效并发控制。
- 插入、删除、查找平均时间复杂度为 O(log n)
- 所有操作都是线程安全的,且不阻塞整个结构
- 适用于读写混合、高并发、需排序的场景
对比 synchronized TreeMap:后者在高并发下容易成为瓶颈,因为每次操作都需获取对象锁;而 ConcurrentSkipListMap 只锁定局部节点,提升吞吐量。
3. 常用有序操作与并发技巧
利用其 NavigableMap 特性,可以高效执行范围查询和定位操作:
- map.firstEntry():获取最小键值对
- map.lastKey():获取最大键
- map.lowerEntry(k):小于 k 的最大键值对
- map.subMap(fromKey, toKey):获取闭开区间的视图
- map.headMap(toKey):获取小于某键的所有条目
这些方法返回的视图也是线程安全的,适合用于实时监控、滑动窗口、优先级队列等场景。
例如:实现一个按时间戳排序的任务调度缓存:
ConcurrentSkipListMaptasks = new ConcurrentSkipListMap<>(); // 添加任务(时间戳作为 key) tasks.put(System.currentTimeMillis() + 5000, () -> System.out.println("Delay task")); // 扫描并执行到期任务 long now = System.currentTimeMillis(); ConcurrentNavigableMap expired = tasks.headMap(now, true); expired.values().forEach(Runnable::run); expired.clear(); // 安全清除已执行任务
4. 使用注意事项与最佳实践
虽然功能强大,但使用时仍需注意以下几点:
- key 必须实现 Comparable 接口,或传入 Comparator,否则运行时报错
- 不允许 null 键和 null 值(会抛 NullPointerException)
- 迭代器弱一致性:不会抛出 ConcurrentModificationException,但可能不反映最新修改
- 在遍历过程中不要依赖强一致性,适合“快照式”处理
建议配合原子操作或业务逻辑判断,避免竞态条件。例如用 putIfAbsent 实现幂等缓存:
String result = map.putIfAbsent(key, computeExpensiveValue());
if (result == null) {
result = map.get(key); // 刚放入的值
}
基本上就这些。ConcurrentSkipListMap 在需要排序+并发的场景中非常实用,合理使用能显著提升系统性能和可维护性。不复杂但容易忽略细节,掌握好它的特性就能发挥出最大价值。










