➤ How to Code a Game
➤ Array Programs in Java
➤ Java Inline Thread Creation
➤ Java Custom Exception
➤ Hibernate vs JDBC
➤ Object Relational Mapping
➤ Check Oracle DB Size
➤ Check Oracle DB Version
➤ Generation of Computers
➤ XML Pros & Cons
➤ Git Analytics & Its Uses
➤ Top Skills for Cloud Professional
➤ How to Hire Best Candidates
➤ Scrum Master Roles & Work
➤ CyberSecurity in Python
➤ Protect from Cyber-Attack
➤ Solve App Development Challenges
➤ Top Chrome Extensions for Twitch Users
➤ Mistakes That Can Ruin Your Test Metric Program
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
- ConcurrentMap(I)
The ConcurrentMap interface defines many methods. Some of the mostly used methods are as follows:-
- putIfAbsent()
- remove()
- 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
- The underlying data structure is Hashtable.
- ConcurrentHashMap allows concurrent read and thread-safe update operations.
- 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).
- Concurrent update achieved by internally dividing Map into smaller portions which is defined by concurrency level.
- The default concurrency level is 16.
- ConcurrentHashMap allows simultaneous multiple-read operations but simultaneously only 16 write/update operations.
- Null is not allowed for both keys and values.
- 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:-
Main thread iterating map & current entry is: 101…A
Child thread updating map
Exception in thread “main” java.util.ConcurrentModificationException
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:-
Main thread iterating map & current entry is: 101…A
Child thread updating map
Main thread iterating map & current entry is: 102…B
Main thread iterating map & current entry is: 103…C
{101=A, 102=B, 103=C}
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
ConcurrentHashMap | synchronizedMap() | 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!