ConcurrentMap Interface in Java

ConcurrentMap Interface in Java | We have seen why Concurrent collection was introduced and the difference between traditional collection (java.util package) vs concurrent collection (java.util.concurrent package).

  • Map(I)
    • ConcurrentMap(I)
      • ConcurrentHashMap class

The ConcurrentMap interface defines many methods. Some of the mostly used methods are as follows:-

  1. putIfAbsent()
  2. remove()
  3. replace()

putIfAbsent() Method of ConcurrentMap Interface in Java

Method signature:- V putIfAbsent(K key, V value);

To add an entry to the map if the specified key is not already available. It works like this:-

V putIfAbsent(K key, V value) {
   if(!map.containsKey(key)) {
      map.put(key, value);
   } else {
      return map.get(key);
   }
}

Demonstration of putIfAbsent() Method:-

import java.util.concurrent.ConcurrentHashMap;

public class Test extends Thread {
    public static void main(String[] args) {
        ConcurrentHashMap<Integer, String> chm = new ConcurrentHashMap<>();
        chm.put(101, "Java");
        chm.putIfAbsent(101, "Python");
        System.out.println(chm); // {101=Java}
    }
}
put()putIfAbsent()
If the key is already available then the old value will be replaced with a new value and returns the old value.If the key is already present then the Entry won’t be added and returns the old associated value. If the key is not available then only Entry will be added.
chm.put(101, "AAAA");
chm.put(101, "BBBB");
System.out.println(chm); // {101=BBBB}
chm.put(101, "AAAA");
chm.putIfAbsent(101, "BBBB");
System.out.println(chm); // {101=AAAA}

remove(key, value) Method of ConcurrentMap Interface in Java

Method prototype:- boolean remove(Object key, Object value)

It removes the entry if the key is associated with the specified value. It works as follows:-

Object remove(Object key, Object value) {
   if(map.containsKey(key) && 
      map.get(key).equals(value) ) {
    
      map.remove(key);
      return true;
   } else {
      return false;
   }
}

Demonstration of remove(key, value) method:-

import java.util.concurrent.ConcurrentHashMap;

public class Test extends Thread {
    public static void main(String[] args) {
        ConcurrentHashMap<Integer, String> chm = new ConcurrentHashMap<>();
        chm.put(101, "Java");
        System.out.println(chm.remove(101, "Python")); // false
        System.out.println(chm); // {101=Java}
        System.out.println(chm.remove(101, "Java")); // true
        System.out.println(chm); // {}
    }
}
remove(key)remove(key, value)
It removes the entry if the key is matched.It removes the entry if both key and value are matched, and returns true. If key and value are not matched then it returns false.
chm.put(101, "AAAA");
chm.remove(101);
System.out.println(chm); // {}
chm.put(101, "AAAA");
chm.remove(101, "BBBB"); // false System.out.println(chm); // {101=AAAA}
chm.remove(101, "AAAA"); // true
System.out.println(chm); // {}

replace(key, oldValue, newValue) Method of ConcurrentMap Interface in Java

Method Signature:- boolean replace(K key, V oldValue, V newValue)

If the key and oldValue matched then replace oldValue with newValue. It works as follows:-

boolean replace(K key, V oldValue, V newValue) {
   if(map.containsKey(key) && map.get(key).equals(oldValue) ) {
      map.put(key, newValue);
      return true;
   } else {
      return false;
   }
}

Demonstration of replace(key, oldValue, newValue) method:-

import java.util.concurrent.ConcurrentHashMap;

public class Test extends Thread {
    public static void main(String[] args) {
        ConcurrentHashMap<Integer, String> chm = new ConcurrentHashMap<>();
        chm.put(101, "Java");
        chm.replace(101, "Know", "Python");
        System.out.println(chm); // {101=Java}
        chm.replace(101, "Java", "Python");
        System.out.println(chm); // {101=Python}
    }
}

ConcurrentHashMap Class in Java

  1. The underlying data structure is Hashtable.
  2. ConcurrentHashMap allows concurrent read and thread-safe update operations.
  3. To perform read operation thread won’t require any Lock. But to perform an update operation thread requires a lock but it is the lock of only a particular part of the Map (segment lock or bucket level lock).
  4. Concurrent update achieved by internally dividing Map into smaller portions which is defined by concurrency level.
  5. The default concurrency level is 16.
  6. ConcurrentHashMap allows simultaneous multiple-read operations but simultaneously only 16 write/update operations.
  7. Null is not allowed for both keys and values.
  8. While one thread iterates, another thread can perform an update operation and ConcurrentHashMap never throws ConcurrentModificationException.

How ConcurrentHashMap improves the performance compared with Hashtable. In Hashtable for performing any operation thread requires the lock of the complete Map object but in the case of ConcurrentHashMap thread won’t require total map object lock. Instead, Thread requires segment lock or bucket level lock.

At a time how many threads are allowed to perform read operations simultaneously?
Multiple threads (Any number of threads). They don’t require any lock.

At a time how many threads are allowed to perform update operations simultaneously?
By default 16 threads.

Hence waiting time for threads gets reduced and the performance of the system will be improved.

Concurrency level and number of buckets most of the time are the same. Therefore for every bucket a separate lock by default will be maintained.

Default Initial capacity = 16
Concurrency level = 16

15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0

Concurrency level and initial capacity most of the time are same but need not be the same always. If both are the same then for 1 bucket, 1 lock is allocated. If both are not the same then based on concurrency level and initial capacity locks will be adjusted.

Assume,
Default Initial capacity = 16
Concurrency level = 8
Then for every 2 bucket one lock will be maintained.

Similarly,
Default Initial capacity = 16
Concurrency level = 32
Then for every bucket 2 locks will be maintained.

Constructors of ConcurrentHashMap

  • ConcurrentHashMap(); It creates an empty ConcurrentHashMap with a default initial capacity of 16, a default fill ratio of 0.75, and default concurrency level = 16.
  • ConcurrentHashMap(int initialCapacity);
  • ConcurrentHashMap(int initialCapacity, float fillRatio);
  • ConcurrentHashMap(int initialCapacity, float fillRatio, int concurrencyLevel);
  • ConcurrentHashMap(Map m);
import java.util.concurrent.ConcurrentHashMap;

public class Test extends Thread {
    public static void main(String[] args) {
        ConcurrentHashMap<Integer, String> chm = new ConcurrentHashMap<Integer, String>();
        chm.put(101, "A");
        chm.put(102, "B");
        chm.putIfAbsent(103, "C");
        chm.putIfAbsent(101, "D");
        chm.remove(101, "D");
        chm.replace(102, "B", "E");
        System.out.println(chm); // {101=A, 102=E, 103=C}
    }
}

ConcurrentHashMap is the best choice if the huge number of threads are working simultaneously.

While one thread iterating HashMap the other threads are not allowed to modify the HashMap object. Otherwise, we will get Runtime exception:- ConcurrentModificationException.

Let us demonstrate ConcurrentModificationException through the example:-

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class Test extends Thread {
    static Map<Integer, String> map = new HashMap<Integer, String>();

    public void run() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException ie) {
        }
        System.out.println("Child thread updating map");
        map.put(103, "C");
    }

    public static void main(String[] args) throws Exception {
        map.put(101, "A");
        map.put(102, "B");

        // create another thread
        Test test = new Test();
        test.start();

        // iterate Map
        Set<Integer> s1 = map.keySet();
        Iterator<Integer> itr = s1.iterator();
        while (itr.hasNext()) {
            Integer i1 = (Integer) itr.next();
            System.out.println("Main thread iterating" 
                + " map & current entry is: " + i1 + "..." + map.get(i1));
            Thread.sleep(3000);
        }
        System.out.println(map);
    }

}

Output:-

While one thread iterates ConcurrentHashMap another threads are allowed to modify the ConcurrentHashMap object in safe manner and it won’t throw ConcurrentModificationException.

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

Output:-

Note:- While one thread iterating ConcurrentHashMap, and if the other thread trying to perform any modification then there is no guarantee that modification value will be available to the iterator.

ConcurrentHashMap vs synchronizedMap() vs Hashtable

ConcurrentHashMapsynchronizedMap()Hashtable
We will get thread safety without locking the total Map object just with bucket-level lock.We will get thread safety by locking the whole Map object.We will get thread safety by locking the whole Map object.
At a time multiple threads are allowed to operate on Map object in safe manner.At a time only one thread is allowed to perform any operation on the Map object.At a time only one thread is allowed to perform any operation on the Map object.
Read operation can be performed without lock but write operation can be performed with bucket level lock.Every read and write operations require a complete Map object lock.Every read and write operations require a complete Map object lock.
While one thread iterates Map the other threads are allowed to modify the Map object in safe manner and it won’t throw ConcurrentModificationException.While one thread iterates Map the other threads are not allowed to modify the Map object. Otherwise, we will get Runtime exception:- ConcurrentModificationException.While one thread iterates Map the other threads are not allowed to modify the Map object. Otherwise, we will get Runtime exception:- ConcurrentModificationException.
The iterator of ConcurrentHashMap is fail-safe and it won’t throw ConcurrentModificationException.The iterator of synchronizedMap() is fail-fast and it throws ConcurrentModificationException.The iterator of Hashtable is fail-fast and it throws ConcurrentModificationException.
Null is not allowed for both keys and values otherwise we will get NullPointerException.Null is allowed for both keys and values.Null is not allowed for both keys and values otherwise we will get NullPointerException.
Introduced in the 1.5 version.Introduced in the 1.2 version.Introduced in the 1.0 version.

If you enjoyed this post, share it with your friends. Do you want to share more information about the topic discussed above or do you find anything incorrect? Let us know in the comments. Thank you!

Leave a Comment

Your email address will not be published. Required fields are marked *