ConcurrentSkipListSet in Java: Complete Enterprise Guide with Real-Time Microservice Examples
ConcurrentSkipListSet is a thread-safe sorted set implementation available in Java's java.util.concurrent package. It is designed for applications where multiple threads need to read and modify sorted data at the same time.
Unlike TreeSet, which uses a Red-Black Tree and requires external synchronization, ConcurrentSkipListSet internally uses a Skip List data structure designed for concurrent access.
Why Do We Need ConcurrentSkipListSet?
Modern enterprise systems are highly concurrent. Multiple threads, API requests, Kafka consumers, background jobs, and WebSocket connections may access the same data simultaneously.
Trading System Example
Kafka Thread
|
v
Update Stock Price
REST API Thread
|
v
Read Current Prices
Scheduler Thread
|
v
Publish Market DataIf all these threads share a normal TreeSet, synchronization problems can occur. ConcurrentSkipListSet solves this problem by providing thread-safe operations.
ConcurrentSkipListSet Features
- Thread-safe collection
- Maintains sorted order
- Does not allow duplicates
- Supports concurrent reads and writes
- Provides NavigableSet operations
- Does not lock the complete collection
Internal Working of ConcurrentSkipListSet
ConcurrentSkipListSet internally uses ConcurrentSkipListMap. Similar to TreeSet using TreeMap internally, ConcurrentSkipListSet stores elements as keys inside ConcurrentSkipListMap.
ConcurrentSkipListSet
|
v
ConcurrentSkipListMap
|
v
Skip List Data StructureWhat is a Skip List?
A Skip List is a probabilistic data structure that creates multiple levels of linked lists. Higher levels allow faster searching by skipping unnecessary nodes.
Level 3:
10 ---------------------- 90
Level 2:
10 -------- 50 -------- 90
Level 1:
10 --20--30--50--70--90The bottom level contains all elements. Higher levels contain selected elements that act like shortcuts.
Skip List Searching
Search for 70
Start at highest level
|
v
Jump over large sections
|
v
Move downward when required
|
v
Find element quicklyAverage search complexity is O(log n), similar to balanced trees.
How ConcurrentSkipListSet Handles Multiple Threads
ConcurrentSkipListSet does not use one large lock around the complete collection. Instead, it uses fine-grained atomic operations internally.
Thread 1
|
v
Insert Node A
Thread 2
|
v
Remove Node B
Thread 3
|
v
Read Data
All operations continue safelyHow ConcurrentSkipListSet Adds an Element Internally
When an element is added, ConcurrentSkipListSet internally delegates the operation to ConcurrentSkipListMap. The map searches the correct position in the Skip List and inserts the new node using concurrent algorithms.
add(stockPrice)
|
v
Compare using Comparator
|
v
Find position in Skip List
|
v
Create new node
|
v
CAS operation updates links
|
v
Element added safelyCAS (Compare And Swap) is a hardware-supported atomic operation that allows threads to update values safely without locking the entire data structure.
ConcurrentSkipListSet Duplicate Handling
Similar to TreeSet, ConcurrentSkipListSet uses Comparator or Comparable to decide whether two elements are duplicates.
ConcurrentSkipListSet<Integer> numbers =
new ConcurrentSkipListSet<>();
numbers.add(100);
numbers.add(100);
System.out.println(numbers);Output: [100]. The second value is ignored because comparison returns zero.
Real World Problem: Stock Price Duplicate Values
A common mistake is sorting stock only by price. Different companies can have the same stock price.
AAPL 200
GOOGLE 200
Comparator:
200 == 200
Result:
One stock removedCorrect Stock Comparator
ConcurrentSkipListSet<StockPrice> stocks =
new ConcurrentSkipListSet<>(
Comparator.comparing(StockPrice::getPrice)
.thenComparing(StockPrice::getSymbol)
);Now price is the primary sorting field and stock symbol becomes the unique identifier.
Real World Example: Stock Trading Microservice
Trading platforms need to process thousands of price updates every second. Multiple parts of the system access the same market data.
Stock Exchange
|
v
Kafka Topic
|
v
Price Consumer
|
v
ConcurrentSkipListSet
/ | \
/ | \
REST API WebSocket Risk EngineStockPrice Entity
public class StockPrice {
private String symbol;
private double price;
public StockPrice(String symbol,double price){
this.symbol = symbol;
this.price = price;
}
public String getSymbol(){
return symbol;
}
public double getPrice(){
return price;
}
}Price Book Service
@Service
public class PriceBook {
private final ConcurrentSkipListSet<StockPrice> prices =
new ConcurrentSkipListSet<>(
Comparator.comparing(StockPrice::getPrice)
.thenComparing(StockPrice::getSymbol)
);
public void updatePrice(StockPrice stock){
prices.remove(stock);
prices.add(stock);
}
public Set<StockPrice> getPrices(){
return prices;
}
}This service object is shared by multiple Spring Boot threads. The collection remains safe because ConcurrentSkipListSet supports concurrent access.
Kafka Consumer Updating Prices
@Component
public class PriceConsumer {
private final PriceBook priceBook;
public PriceConsumer(PriceBook priceBook){
this.priceBook = priceBook;
}
@KafkaListener(topics="stock-price")
public void consume(StockPrice price){
priceBook.updatePrice(price);
}
}Kafka continuously pushes market updates. Each message is processed by a consumer thread that updates the sorted set.
REST API Reading Live Stock Prices
The REST API thread can read the latest sorted market prices while Kafka threads are updating the collection. No explicit synchronization is required.
@RestController
@RequestMapping("/market")
public class MarketController {
private final PriceBook priceBook;
public MarketController(PriceBook priceBook){
this.priceBook = priceBook;
}
@GetMapping("/prices")
public Set<StockPrice> getPrices(){
return priceBook.getPrices();
}
}While this API executes, other threads may add or remove prices. The iterator remains safe because ConcurrentSkipListSet provides weakly consistent iteration.
What is Weakly Consistent Iterator?
Normal collections like TreeSet throw ConcurrentModificationException when a collection changes during iteration. ConcurrentSkipListSet does not fail immediately.
Thread 1:
for(price : prices)
display price
Thread 2:
prices.add(newPrice)
Result:
Iterator continues safelyThe iterator may or may not see the newly added element, but it will never corrupt the collection.
WebSocket Real-Time Price Broadcasting
Trading applications use WebSockets to push live updates to thousands of users. A scheduler can periodically read the ConcurrentSkipListSet and publish data.
@Component
public class MarketPublisher {
private final PriceBook priceBook;
public MarketPublisher(PriceBook priceBook){
this.priceBook = priceBook;
}
@Scheduled(fixedRate = 1000)
public void publish(){
Set<StockPrice> prices =
priceBook.getPrices();
// send through websocket
}
}Three different workloads are running together: Kafka updates, REST reads, and WebSocket publishing.
Kafka Consumer Thread
|
v
Add / Update Prices
|
v
ConcurrentSkipListSet
^
|
|
REST Controller Thread
|
v
Customer Request
^
|
Scheduler Thread
|
v
WebSocket BroadcastRange Search in ConcurrentSkipListSet
Because ConcurrentSkipListSet maintains sorted order, it supports NavigableSet operations.
NavigableSet<StockPrice> selected =
prices.subSet(
new StockPrice("",100),
true,
new StockPrice("ZZZ",200),
true
);This can be used for finding stocks within a price range, filtering players in a leaderboard range, or selecting jobs based on priority.
Finding Highest and Lowest Price
StockPrice highest = prices.last();
StockPrice lowest = prices.first();A trading dashboard can quickly display the highest and lowest traded prices.
Example: Gaming Leaderboard System
Another common enterprise use case is an online gaming leaderboard. Thousands of players complete matches simultaneously and their rankings must remain sorted.
Game Server
|
v
Score Events
|
v
Leaderboard Service
|
v
ConcurrentSkipListSet
|
v
Top Players APIPlayer Entity
public class Player {
private Long id;
private String name;
private int score;
public Long getId(){
return id;
}
public int getScore(){
return score;
}
public String getName(){
return name;
}
}Leaderboard Implementation
@Service
public class LeaderboardService {
private final ConcurrentSkipListSet<Player> players =
new ConcurrentSkipListSet<>(
Comparator.comparing(Player::getScore)
.reversed()
.thenComparing(Player::getId)
);
public void update(Player player){
players.remove(player);
players.add(player);
}
public Set<Player> getLeaderboard(){
return players;
}
}Multiple game servers can update player scores while users request leaderboard data.
ConcurrentSkipListSet Performance Analysis
ConcurrentSkipListSet provides almost the same average complexity as TreeSet but is designed for concurrent environments.
- add() operation: O(log n) average
- remove() operation: O(log n) average
- contains() operation: O(log n) average
- first() operation: O(log n)
- last() operation: O(log n)
- Iteration: O(n)
TreeSet vs ConcurrentSkipListSet Internal Difference
Why Not Use synchronized TreeSet Everywhere?
Developers can synchronize TreeSet manually, but it creates a single lock. When thousands of operations happen simultaneously, threads wait for each other.
Synchronized TreeSet
Thread 1
|
v
Acquire Lock
|
v
Update Tree
|
v
Release Lock
Thread 2 waits...ConcurrentSkipListSet allows multiple threads to continue operating using internal atomic techniques.
When Should Companies Use ConcurrentSkipListSet?
- Real-time trading systems
- Live gaming leaderboards
- High-frequency event processing
- Real-time monitoring dashboards
- Distributed schedulers
- Priority based processing systems
When Should Companies Avoid ConcurrentSkipListSet?
ConcurrentSkipListSet is powerful but should not be used everywhere. It has additional memory overhead compared with simple collections.
- When sorting is not required use HashSet
- When data is local and single threaded use TreeSet
- When insertion order matters use LinkedHashSet
- When data is extremely small avoid unnecessary concurrency overhead
Memory Consideration
Skip Lists maintain multiple levels of references. Because of this, ConcurrentSkipListSet may consume more memory than a normal TreeSet.
TreeSet
Node
|
|-- Left
|-- Right
Skip List
Node
|
|-- Next Level Pointer
|-- Next Level Pointer
|-- Next NodeProduction Architecture: Real-Time Market Data Platform
A modern financial platform can use ConcurrentSkipListSet as an in-memory sorted view of rapidly changing market data.
Exchange Feed
|
v
Kafka Cluster
|
v
Market Data Service
|
v
ConcurrentSkipListSet
|
+--------------+
| |
v v
REST API WebSocket API
|
v
Mobile UsersFuture Scope of ConcurrentSkipListSet
As systems become more real-time and event driven, concurrent sorted collections become increasingly valuable. They provide fast in-memory processing before data is persisted into distributed storage.
- Real-time AI recommendation ranking
- Autonomous vehicle event prioritization
- IoT sensor monitoring
- High frequency trading systems
- Cloud based distributed schedulers
- Real-time fraud detection
Future Example: AI Recommendation Engine
Streaming platforms continuously calculate user recommendations. Multiple machine learning workers update scores while users request recommendations.
User Events
|
v
AI Model
|
v
Recommendation Scores
|
v
ConcurrentSkipListSet
|
v
Top RecommendationsConcurrentSkipListSet Interview Questions
- Why was ConcurrentSkipListSet introduced?
- How is it different from TreeSet?
- Which data structure is used internally?
- How does Skip List achieve O(log n)?
- What is weakly consistent iteration?
- Does ConcurrentSkipListSet allow duplicates?
- How does it support multiple threads?
- When should you choose ConcurrentSkipListSet?
Final Summary
- ConcurrentSkipListSet is a thread-safe sorted set
- It internally uses ConcurrentSkipListMap
- Its internal structure is a Skip List
- It supports concurrent reads and writes
- It maintains sorted unique elements
- Comparator decides duplicate detection
- It is suitable for real-time enterprise systems
- It is commonly used with Kafka, WebSocket, and event-driven systems
- Use it when concurrency and ordering are both required
ConcurrentSkipListSet is an important collection for modern Java enterprise applications because it combines two difficult requirements: maintaining sorted data and supporting high concurrency. It is especially valuable in real-time systems where multiple services continuously read and update shared information.