ConcurrentSkipListMap keeps keys ordered while permitting concurrent updates. Its range views restrict keys by boundary, but a traversal during writes is not a frozen report.
Java ConcurrentSkipListMap: inspect an ordered time window
Operational contract
The sample stores delivery events under unique sequence numbers and reads the half-open interval [firstInclusive, lastExclusive). The returned subMap is backed by the live map. Copying up to 47 entries into a list limits this method's result size but does not give an instantaneous snapshot. A separate transaction, version, or pause protocol is needed when the report must represent one exact point in time. The map rejects null keys and values. A single sequence per event prevents one event from overwriting another with the same timestamp.
Failure case
A dispatch console asks for events numbered 240 through 286 while another worker inserts event 261. The range excludes event 287 by definition, but its iteration may or may not see event 261 depending on timing. The console may use that list for monitoring; it must not certify a ledger from it.
Java code
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentSkipListMap;
public class DispatchSequenceWindow {
private final ConcurrentSkipListMap<Long, String> events = new ConcurrentSkipListMap<>();
public void record(long sequence, String eventId) {
if (events.putIfAbsent(sequence, eventId) != null)
throw new IllegalArgumentException("Sequence already assigned");
}
public List<String> read(long firstInclusive, long lastExclusive) {
if (firstInclusive > lastExclusive) throw new IllegalArgumentException("Reversed window");
List<String> selected = new ArrayList<>();
for (String eventId : events.subMap(firstInclusive, true, lastExclusive, false).values()) {
if (selected.size() == 47) throw new IllegalStateException("Window exceeds 47 events");
selected.add(eventId);
}
return List.copyOf(selected);
}
}Performance and ownership cost
An ordered insertion or boundary lookup has expected O(log N) work for N entries. Copying R visible entries costs O(R) time and O(R) result memory, capped here at 47. The live range still retains its backing map; this sample does not bound the map's total size.
Common Mistakes
- Do not treat a backed range view as an immutable copy.
- Do not use weakly consistent iteration for an exact financial snapshot.
- Do not key distinct events by a timestamp that can collide.
Connected lessons
- Java ConcurrentSkipListMap: ordered concurrent lookups and live ranges
- Java ConcurrentHashMap: atomic updates and weakly consistent reads
- Java Iterator and ListIterator: traversal and controlled edits
- Java ConcurrentHashMap.computeIfAbsent: create a counter once per key
- Java CopyOnWriteArrayList: dispatch against a listener snapshot
- Java AtomicReference: publish one immutable map snapshot
- Java concurrent state and handoff quiz
- Advanced Java
