How to Create a Thread-Safe ConcurrentHashSet in Java?


In this article, we will see what are the possibilities available to create thread-safe HashSet instances and see what will be equivalent to ConcurrentHashMap for HashSet. We will also look at the benefits and drawbacks of each approach.

Before JDK8 we are not able to create a Thread Safe ConcurrentHashMap because  java.util.concurrent package in JDK8 does not provide a class named ConcurrentHashSet, two new methods were added that are discussed below. ConcurrentHashMap is the Map implementation that allows us to modify the Map while iterating. The ConcurrentHashMap operations are thread-safe. ConcurrentHashMap doesn't allow null for keys and values.

Ways to Create Thread-safe ConcurrentHashSet

When Coming to ConcurrentHashSet can be created by utilizing ConcurrentHashMap, which enables the use of keySet(default Value) and newKeySet() methods to obtain a proper Set. This provides access to functions such as contains(), remove(), and more.

  • keySet (Default Value)

  • newKeySet()

Creating ConcurrentHashSet Using KeySet(default Value)

The keySet(default Value) method of the ConcurrentHashMap class provides a Set view of the keys stored in the map. The set is supported by the map itself, meaning that modifications to the map will be reflected in the set, and vice versa.

Syntax

public ConcurrentHashMap.KeySetView<K,V> keySet(default_value)

Parameter

Passing default_value while creating a set using ConcurrentHashMap

Example

//A Java program to demonstrate the implementation of a ConcurrentHashSet that ensures thread safety.

import java.io.*;
import java.util.*;

public class TutorialsPoint {
   public static void main (String[] args) {

      ConcurrentHashMap<String,Integer> map = new ConcurrentHashMap<>();

      map.put("Tutorials",1);
      map.put("Point",2);
      map.put("Java", 3);
      map.put("article on",4);
      map.put("Threads", 5);

      //Create a Set using concurrenthashmap
      Set intialSet = map.keySet(120); //The value 120 is an arbitrary default value
      System.out.println("Initial set: " + intialSet);

      // The value will remain unchanged as 120
      // but no error will be encountered.

      intialSet.add("Element");
      System.out.println("After removing an element " + intialSet);

      //Checking if the set contains if yes we will remove and print the set

      if(intialSet.contains("Threads")) {
         intialSet.remove("Threads");
         System.out.println("After removing an element " + intialSet);
      }
   }
}

Output

Initial set: [Threads, Java, Tutorials, Point, article on]
After removing an element [Threads, Java, Tutorials, Element, Point, article on]
After removing an element [Java, Tutorials, Element, Point, article on]

Drawback

While trying to add a new element to the set the value will remain the same i.e the value that we have set as default while creating a set.

Due to all the limitations that we are facing above that’s why they introduced the newKeySet() method that returns a Set that is backed by a ConcurrentHashMap, where the values associated with the keys are of type Boolean.

How to Create ConcurrentHashSet Using NewKeySet()

The newKeySet() method belongs to the ConcurrentHashMap class which generates a new set supported by a ConcurrentHashMap, with elements of the specified type mapped to Boolean.TRUE.

Syntax

public static <K> ConcurrentHashMap.KeySetView<K,Boolean> newKeySet()

Code that is present below will give us an idea how to create a ConcurrentHashSet using newKeySet(). To resolve all the issues that we face in the 1st approach we will now use newkeySet().

Example

// A Java program to demonstrate the implementation of a ConcurrentHashSet that ensures thread safety.

import java.io.*;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class TutorialsPoint {
   public static void main (String[] args) {

      // Creating a map
      ConcurrentHashMap<String,Integer> map = new ConcurrentHashMap<>();

      map.put("Tutorials",1);
      map.put("Point",2);
      map.put("Java", 3);
      map.put("article on",4);
      map.put("Threads", 5);

      Set <String> subjectsSet = ConcurrentHashMap.newKeySet();

      subjectsSet.add("Computer Networks");
      subjectsSet.add("DBMS");
      subjectsSet.add("OS");

      // displaying the values of set
      System.out.println("before adding an element into subjects set: " + subjectsSet);

      //use add() method to insert elements into the set
      subjectsSet.add("DSA");

      // Print the set again to verify the changes
      System.out.println("after adding an element into subjects set: " + subjectsSet);

      // we can use utilize contains() method to check presence of an element in a  set
      if(subjectsSet.contains("DSA"))
      System.out.println("Yes it is there");
      else
      System.out.println("No it is not there");

      // we can do it directly like this :subjectsSet.contains("DSA")); it returns boolean value

      // To remove an element from a set use remove() method
      subjectsSet.remove("OS");
      System.out.println("after removing an element from subjects set: " + subjectsSet);
   }
}

Output

before adding an element into subjects set: [Computer Networks, OS, DBMS]
after adding an element into subjects set: [Computer Networks, DSA, OS, DBMS]
Yes it is there
after removing an element from subjects set: [Computer Networks, DSA, DBMS]

We have other ways also to create thread-safe HashSet but not used mostly and also less efficient than the ones which we discussed above.

ConcurrentHashSet Using Collections Utility Class

The synchronizedSet() method which belongs to Java Collections class is employed to obtain a synchronized (thread-safe) set, which is supported by the specified set.

In this method, we utilize the synchronizedSet() method provided by java.util.Collections to create a HashSet instance that is thread-safe.

Syntax

public static <T> Set<T> synchronizedSet(Set<T> s)

Parameter

This set is encapsulated within a synchronized set.

Example

import java.io.*;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Collections;
import java.util.HashSet;

public class TutorialsPoint {
   public static void main (String[] args) {

      Set<String> names= new HashSet<String>();
      //let’s Add values to the set using add()
      names.add("Hari");
      names.add("Revanth");
      names.add("Lokesh");
      names.add("Kiran");
      //Creating a synchronized set
      Set<String> synchronizedSet = Collections.synchronizedSet(names);
      System.out.println("Synchronized set is :"+synchronizedSet );
   }
}

Output

Synchronized set is :[Revanth, Hari, Kiran, Lokesh]

It is less efficient than the ones that are discussed above. Basically synchronizedSet() wraps Set into synchronized decorator when compared with ConcurrentHashMap that implements a low-level concurrency mechanism.

Thread Safe Set Using CopyOnWriteArraySet

The last approach that is used to create thread-safe implementations is CopyOnWriteArraySet. Below is the code snippet for creating an instance of Set.

Example

Set<String> copyOnArraySet = new CopyOnWriteArraySet<>();
copyOnArraySet.add("sample");

The following are the some important properties and the drawbacks that we need to consider −

  • It uses an array not a HashMap to store the data which means the operations like contains() or remove() have O(n) complexity when compared to ConcurrentHashMap that takes O(1).

  • It is suited for very small applications and we need to prevent interference between the threads during traversal.

  • Rasters do not provide operations to erase variables.

Conclusion

In this article we have seen various possibilities to create thread-safe Set instances. Initially, we explored the creation of a ConcurrentHashSet in Java, which is backed by ConcurrentHashMap. and the differences between those methods and this should be the first choice when a thread-safe hash set is needed.

Finally we also discussed synchronizedSet(),CopyOnWriteArraySet approaches and their performance drawbacks.

Updated on: 16-Oct-2023

107 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements