ConcurrentHashMap
ConcurrentHashSet
Java Programming
Multithreading
Data Structures

Why there is no ConcurrentHashSet against ConcurrentHashMap

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

In Java, the ConcurrentHashMap is a popular choice among developers when dealing with multi-threading environments due to its thread-safety features and efficient scalability. On the contrary, there isn't a direct counterpart named ConcurrentHashSet in the Java Collections Framework. Understanding the reason behind this can be quite enlightening for Java developers and enthusiasts alike.

Understanding the Basics: ConcurrentHashMap and HashSet

First, let’s briefly review the purpose and functionality of ConcurrentHashMap and HashSet. The ConcurrentHashMap is a hash table supporting full concurrency of retrievals and adjustable expected concurrency for updates. It handles concurrent modifications gracefully, largely by part-locking its segments, thus allowing concurrent threads to usually operate without interference. This makes it considerably ideal for high-throughput applications.

HashSet, on the other hand, implements the Set interface, backed by a hash table (actually a HashMap instance). It does not allow duplicate entries, and just like HashMap, it is not thread-safe unless externally synchronized.

Why No ConcurrentHashSet?

Interestingly, there is no direct concurrent counterpart to HashSet such as ConcurrentHashSet. The reason lies primarily in Java’s design choice which favors composition over direct extension. In fact, Java provides all functionalities to implement a concurrent set using the existing ConcurrentHashMap.

To create a thread-safe set using ConcurrentHashMap, you can simply back a Set with a ConcurrentHashMap wherein you utilize the keys of the map as the elements of your set. Since the values of the map do not contribute to the characteristics of the set, they can be arbitrary — usually an Object placeholder (like Object()) or Boolean.TRUE is used.

Here’s a simple implementation of a thread-safe set using ConcurrentHashMap:

java
1import java.util.Collections;
2import java.util.Set;
3import java.util.concurrent.ConcurrentHashMap;
4
5public class ConcurrentHashSet<E> extends AbstractSet<E> implements Set<E>, Serializable {
6    private static final Object PRESENT = new Object();
7    private ConcurrentHashMap<E, Object> map;
8    
9    public ConcurrentHashSet() {
10        map = new ConcurrentHashMap<>();
11    }
12
13    public boolean add(E e) {
14        return map.put(e, PRESENT) == null;
15    }
16
17    public boolean remove(Object o) {
18        return map.remove(o) == PRESENT;
19    }
20
21    public boolean contains(Object o) {
22        return map.containsKey(o);
23    }
24
25    public int size() {
26        return map.size();
27    }
28
29    public void clear() {
30        map.clear();
31    }
32}

In the above code, every method of the Set interface is implemented by delegating calls to the corresponding methods of ConcurrentHashMap. This design illustrates the application of composition where ConcurrentHashSet doesn't inherit ConcurrentHashMap but instead manages an instance internally.

Advantages of Using Composition Over Extension

The choice of using composition over extension or direct implementation brings several advantages:

  • Flexibility and Loose Coupling: The set functionality is kept separate from the machinery of the hash map, making it easier to modify or replace implementations without affecting the other.
  • Reusability: The same ConcurrentHashMap can back multiple abstract data types with different behaviors required by various interfaces.

Summarizing Key Points

Here’s a summary table of the discussion:

FeatureConcurrentHashMapConcurrentHashSet
BasisHash tableBacked by ConcurrentHashMap
Thread SafetyFully concurrentDerived from ConcurrentHashMap using composition
DuplicationAllows keysNo duplicate entries
Direct ExtensionNAUtilizes composition instead of extending ConcurrentHashMap

Conclusion

Instead of introducing a redundant ConcurrentHashSet, Java provides the tools and paradigms to compose such a collection using ConcurrentHashMap. This approach demonstrates Java’s commitment to object-oriented design principles such as reusability and loose coupling. Using ConcurrentHashMap to create other concurrent collections like ConcurrentHashSet is both straightforward and elegant, giving Java developers powerful tools to handle multi-threaded scenarios effectively.


Course illustration
Course illustration

All Rights Reserved.