skip to content

What are ConcurrentSkipListMap and ConcurrentSkipListSet, and when would you use them?

level: middleimportance: should knowfreq 50%

answer

  1. Concurrent sorted = TreeMap/TreeSet analogues
  2. Backed by a skip list (layered linked lists), not a red-black tree
  3. Expected O(log n); lock-free via CAS, easy to make concurrent
  4. ConcurrentNavigableMap/Set: ceiling/floor/headMap/subMap, range queries
  5. No nulls; weakly consistent iterators; size() approximate

basics

~20 s

They are thread-safe, sorted map and set classes — the concurrent versions of TreeMap and TreeSet. They keep elements in sorted order and can be used safely by many threads at once, supporting range queries like 'all keys between A and B'.

solid answer

~50 s

ConcurrentSkipListMap and ConcurrentSkipListSet are the concurrent, sorted analogues of TreeMap and TreeSet. They keep keys/elements ordered (by natural ordering or a supplied Comparator) and are fully thread-safe without locking the whole structure, so reads and writes scale across threads. They are backed by a skip list rather than a red-black tree because a skip list is far easier to make lock-free/concurrent: it is a layered linked list where higher levels skip over many nodes, giving expected O(log n) search, insert, and delete. They implement ConcurrentNavigableMap/Set, so you get the navigation and range operations of the sorted interfaces — firstKey, ceilingKey, floorEntry, headMap, tailMap, subMap, descendingMap — all thread-safe. Iterators are weakly consistent (no ConcurrentModificationException). You reach for them when you need a concurrently-accessed structure that also maintains sorted order or supports range/nearest-key queries; if you only need hash lookups without ordering, ConcurrentHashMap is faster.

go deeper

for a junior

Knows they are thread-safe versions of TreeMap/TreeSet that keep things sorted and can be shared by many threads.

for a middle

Can explain they implement ConcurrentNavigableMap/Set with range queries, are O(log n), are skip-list based, and when to prefer ConcurrentHashMap.

for a senior

Explains why a skip list (CAS-friendly, no global rotations) is used over a red-black tree, the probabilistic balancing/height, weakly consistent iterators, no-null and approximate-size caveats.

for a principal

Weighs O(log n) ordered concurrent access vs O(1) hashed access at scale, reasons about comparator cost and memory overhead of skip-list levels, and identifies range-query workloads (time-series, leaderboards) where it's the right structure.

## The need Sometimes you need a thread-safe collection that also keeps its elements **sorted** and supports **range queries** ("give me every key from 100 to 200", "the smallest key ≥ x"). `ConcurrentHashMap` is thread-safe but unordered, and `TreeMap`/`TreeSet` are sorted but *not* thread-safe. The JDK fills the gap with **ConcurrentSkipListMap** (sorted map) and **ConcurrentSkipListSet** (sorted set, internally backed by a skip-list map). ## Key terms (from scratch) - **Sorted / NavigableMap**: a map whose keys are kept in a defined order, exposing navigation methods like `firstKey()`, `lastKey()`, `ceilingKey(k)` (smallest key ≥ k), `floorKey(k)` (largest key ≤ k), and range *views* like `headMap`, `tailMap`, `subMap`. - **Natural ordering / Comparator**: keys are ordered either by their own `compareTo` (natural ordering) or by a `Comparator` you pass to the constructor. - **Red-black tree**: the balanced binary search tree that backs `TreeMap`. Balancing requires rotations that touch several nodes at once, which is hard to do concurrently without coarse locking. - **Skip list**: an alternative ordered structure. Picture a base linked list of all nodes in sorted order, with several *express* linked lists stacked on top, each skipping over more nodes (like express vs local subway lines). To search, you start at the top express lane and drop down a level whenever the next node would overshoot the target, ending at the right spot. A node's height is chosen randomly (probabilistically), which keeps the structure balanced *on average* with expected **O(log n)** search/insert/delete — without the global rebalancing rotations a tree needs. ## Why a skip list for concurrency The whole point is that a skip list is dramatically easier to make **lock-free** than a balanced tree. Inserts and deletes touch only a few `next` pointers along the search path and can be done with **CAS** operations, with no whole-tree rotation. So `ConcurrentSkipListMap` achieves scalable concurrent access (many threads reading and writing) without a global lock — that is why the JDK chose a skip list instead of a concurrent red-black tree. ## Properties and gotchas - **Interfaces**: they implement `ConcurrentNavigableMap` / `ConcurrentNavigableSet`, so all the navigation and range operations are available and thread-safe, and range views (`subMap`, etc.) are live, concurrent sub-views. - **No null keys/values** (a key of `null` can't be ordered). - **Weakly consistent iterators**: they reflect some state at/after creation, never throw `ConcurrentModificationException`, and don't promise a snapshot. - **`size()` is not constant-time and is an estimate**: like other non-blocking collections, it may traverse and is only approximate under concurrent modification — don't rely on it for control flow. - **Performance**: expected O(log n) operations (vs O(1) average for hash maps). Comparisons are done via the key's `compareTo`/`Comparator`, so an inconsistent or expensive comparator hurts correctness/performance. ## ConcurrentHashMap vs ConcurrentSkipListMap — choosing - Need only key→value lookups, no ordering? Use **ConcurrentHashMap** — O(1) average, faster. - Need keys kept **sorted**, or need **range / nearest-key** queries (ceiling/floor/headMap/subMap), concurrently? Use **ConcurrentSkipListMap**. The ordering costs you the jump from O(1) to O(log n). Typical uses: concurrent leaderboards or time-ordered event indexes (range scans by timestamp), priority-by-key structures, or any place you'd want a thread-safe `TreeMap`.

  • Why does the JDK back the concurrent sorted map with a skip list rather than a concurrent red-black tree?
    A balanced tree needs rotations that touch many nodes, which is very hard to do lock-free. A skip list inserts/deletes by CAS-ing a handful of next pointers along the search path, with random node heights for balance — far easier to make scalable and lock-free, at the same expected O(log n).
  • When would you pick ConcurrentHashMap over ConcurrentSkipListMap?
    When you only need hash-style key lookups with no ordering or range queries: ConcurrentHashMap gives average O(1) operations and higher throughput. Use the skip-list map only when you need sorted order or navigation (ceiling/floor/subMap).

saying these in an interview costs you the question

  • Thinking they are O(1) like a hash map — they are O(log n)
  • Saying they are backed by a red-black tree (it's a skip list, chosen for concurrency)
  • Using them when you don't need ordering (ConcurrentHashMap is faster)
  • Expecting an exact, constant-time size() or snapshot iterator
  • Trying to store null keys or values

context