This post will discuss how to create a concurrent set in Java using Guava Sets.newConcurrentHashSet() method.

The Set collection is used to store and manipulate distinct elements. However, sometimes you might want to create a concurrent set that can be safely accessed and modified by multiple threads without explicit synchronization. For example, you might want to use a concurrent set to store the online users of your web application, or the active tasks of your background service. In this post, we will show you how to use the newConcurrentHashSet() method of the Sets class in Guava to create a concurrent set in Java.

1. Overview of newConcurrentHashSet() method

The newConcurrentHashSet() method of the Sets class returns a new instance of a Set that uses a ConcurrentHashMap for its internal implementation. A ConcurrentHashMap is a type of map that supports full concurrency of retrievals and high expected concurrency for updates. This means that multiple threads can read and write to the map without blocking each other, as long as they operate on different keys. The syntax of the Sets.newConcurrentHashSet() method is:

 
The type parameter E is the type of elements in the set. The method returns a new concurrent hash set instance containing the given elements, or an empty set if no elements are specified.

 
The newConcurrentHashSet() method takes an optional parameter of an Iterable or an array that contains the initial elements of the set. Here is an example of using the Sets.newConcurrentHashSet() method:

Download Code

2. Importance of newConcurrentHashSet() method

The newConcurrentHashSet() method is useful when you want to create a concurrent set that can handle concurrent operations efficiently and safely. For example, you might want to:

  • Add or remove elements from the set in different threads without worrying about synchronization or concurrency issues.
  • Iterate over the elements of the set in one thread while modifying them in another thread without throwing ConcurrentModificationException.
  • Perform bulk operations on the set such as containsAll(), addAll(), removeAll(), or retainAll() with high performance and scalability.

All these scenarios can be handled using the newConcurrentHashSet() method, as it returns a set that supports all the methods of the Set interface and inherits the concurrency features of the ConcurrentHashMap. For example:

Download Code

3. Internal working of newConcurrentHashSet() method

You might wonder how the newConcurrentHashSet() method works internally, and whether it affects the performance or memory usage of your program. The answer is that it depends on the size and usage of the set.

The newConcurrentHashSet() method creates a wrapper around a ConcurrentHashMap instance that uses dummy values for its entries. This means that each element of the set is stored as a key in the map, and each value in the map is a constant object that has no meaning. For example, if you create a concurrent set with three elements "a", "b", and "c", the underlying map would look like this:

 
This design allows the concurrent set to delegate all its operations to the underlying map, which handles all the concurrency aspects. For example, when you call users.add("David"), it actually calls map.put("David", DUMMY_VALUE), which returns true if there was no previous entry for "David" in the map, or false otherwise.

The advantage of this design is that it leverages the existing functionality and performance of the ConcurrentHashMap class, which is well-tested and optimized for concurrent access and update. The disadvantage of this design is that it adds some memory overhead for storing the dummy values, which may be significant if you have a large number of elements in your set.

4. Benefits and drawbacks of using the newConcurrentHashSet() method

Using the newConcurrentHashSet() method of the Sets class in Guava has some benefits and drawbacks that you should be aware of before using it. Here are some of the benefits:

  • It is easy to use, as you only need to call one method to create a concurrent set from an Iterable or an array.
  • It is flexible and powerful, as you can use any type of elements that are compatible with the ConcurrentHashMap class, such as objects that implement the equals() and hashCode() methods correctly.
  • It is consistent and thread-safe, as it preserves the immutability and unmodifiability of the elements in the set.
  • It may be confusing or surprising, as it returns a set that is backed by a map, meaning that some methods may behave differently than expected.
  • It may be less performant than a regular set in some cases, such as when using a large number of elements or performing frequent iterations. This is because the newConcurrentHashSet() method may add some memory overhead for storing the dummy values, and some time overhead for delegating the operations to the underlying map.

5. Conclusion

In this post, we have covered how to use the newConcurrentHashSet() method of the Sets class in Guava to create a concurrent set in Java. We have also explained why this method is useful and what are some of the benefits and drawbacks of using it.

If you want to learn more about this method, you can check out the Guava documentation and its GitHub repository.