ConcurrentHashMap is an extensively used class in Java for managing data in multi-threaded environments. It lets in a couple of threads to access the map simultaneously without locking the entire information structure, making it ideal for conditions wherein high-performance access is needed.
Unlike traditional maps, it manages synchronisation in a way that minimises the performance impact, allowing better scaling when multiple threads are working with shared data. This makes it a popular preference for applications where speed and data consistency are essential.
In this blog, we can discover what ConcurrentHashMap is and what are their key features, along with differences from other map implementations.
ConcurrentHashMap is a part of Java’s java.Util.Concurrent package, designed for dealing with maps in multi-threaded environments. It lets in multiple threads to read and write without inflicting data inconsistency. Thanks to its efficient inner locking mechanism which will only lock the part of the map when needed. This ensures overall high performance in comparison to using simple hashmaps.
It divides the map into segments, so only specific segments get locked during updates. This approach allows more threads to work in parallel, making it suitable for scenarios where high concurrency is required. The design helps reduce the contention that can slow down applications.
The class also offers thread-safe operations like putIfAbsent() and computeIfPresent(), which help in performing atomic updates on the map. These features make it a preferred choice when dealing with shared data in concurrent programs.
Get curriculum highlights, career paths, industry insights and accelerate your technology journey.
Download brochure
Syntax of ConcurrentHashMap
The syntax of creating a ConcurrentHashMap in Java follows the general format of other collections but with some specific details. Here’s the basic syntax:
ConcurrentHashMap<K, V> map = new ConcurrentHashMap<>();
In this syntax:
K is the type of key that the map will store.
V is the type of value associated with those keys.
The above line creates an empty ConcurrentHashMap where K and V need to be replaced with the desired data types. For example, if you want a map with String as keys and Integer as values, the syntax would be:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
Example of ConcurrentHashMap
Here’s a basic example of the usage of ConcurrentHashMap in Java. This example demonstrates adding, retrieving, and updating elements inside the map.
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
// Creating a ConcurrentHashMap
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// Adding key-value pairs to the map
map.put("Apple", 3);
map.put("Banana", 5);
map.put("Orange", 10);
// Retrieving a value based on a key
int appleCount = map.get("Apple");
System.out.println("Count of Apples: " + appleCount);
// Updating the value associated with a key
map.put("Banana", 8);
System.out.println("Updated count of Bananas: " + map.get("Banana"));
// Using putIfAbsent to add a key-value pair only if it is not already present
map.putIfAbsent("Grapes", 12);
System.out.println("Count of Grapes: " + map.get("Grapes"));
// Removing a key-value pair
map.remove("Orange");
System.out.println("Is Orange present? " + map.containsKey("Orange"));
}
}
Output
Count of Apples: 3
Updated count of Bananas: 8
Count of Grapes: 12
Is Orange present? false
Explanation:
Creating the Map: We create a ConcurrentHashMap named map with String as the key type and Integer as the value type.
Adding Elements: We add key-value pairs using the put() method. For example, “Apple” is associated with the value 3.
Retrieving Values: The get() method fetches the value associated with a specified key.
Updating Values: We update the value for an existing key using put(), which will overwrite the previous value.
Conditional Insert: The putIfAbsent() method provides a key-fee pair only if the key isn’t always already there.
Removing Entries: The remove() method deletes the specified key-value pair from the map.
Checking Existence: The containsKey() approach tests if a selected specific key is present within the map.
Key Points of ConcurrentHashMap
Here are some key points about ConcurrentHashMap in Java:
Thread-Safe Operations: It allows a couple of threads to get access to and alter the map simultaneously without inflicting record inconsistencies.
Segmented Locking: The map is split into segments, and the only section which is being accessed is now locked.
No Null Keys or Values: Unlike HashMap, it does not allow null keys or values. Trying to add a null will result in a NullPointerException.
Atomic Operations: Provides thread-safe methods such as putIfAbsent(), remove(), and replace() for atomic updates.
Iterators Are Weakly Consistent: The iterators do not throw ConcurrentModificationException and reflect some, but not necessarily all, of the changes made during iteration.
Better Performance Compared to Synchronized Maps: It offers higher scalability because only specific segments are locked instead of the entire map.
Supports Concurrent Reads and Writes: Multiple threads can read from the map and update different segments at the same time, enhancing concurrency.
Customizable Concurrency Level: Allows setting the estimated number of concurrent threads accessing the map, enabling performance tuning.
Memory Overhead: Slightly higher memory usage due to segmented locking and internal structures.
Suitable for High-Concurrency Scenarios: Ideal for applications that require frequent read/write operations with many threads.
Here are the four types of constructors for ConcurrentHashMap in Java, along with code syntax and explanations:
1. ConcurrentHashMap(int initialCapacity)
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(16);
Explanation:
This constructor initialises a ConcurrentHashMap with a special preliminary capacity.
InitialCapacity defines the range of buckets that the map will begin with an initially hold mode.
If the approximate size of the map is known beforehand, you can set the initial capacity and can also help reduce the overall need for resizing, which will automatically improve performance.
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(16, 0.75f);
Explanation:
This constructor allows you to specify both the initial capacity and the load factor.
initialCapacity is the starting size of the map, while loadFactor determines when the map should increase its capacity.
A loadFactor of 0.75 means that the map will resize when 75% of the current capacity is filled.
Setting the load factor can help optimise memory usage and control how often the map resizes.
3. ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel)
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(16, 0.75f, 16);
Explanation:
This constructor allows for setting the initialCapacity, loadFactor, and concurrencyLevel.
concurrencyLevel is the estimated number of threads that will access the map simultaneously.
The map is internally divided into segments, and the concurrencyLevel determines the number of segments.
A higher concurrencyLevel increases the number of segments, which can reduce contention when many threads are accessing the map.
4. ConcurrentHashMap(Map m)
Map<String, Integer> existingMap = new HashMap<>();
existingMap.put("Apple", 3);
existingMap.put("Banana", 5);
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(existingMap);
Explanation:
This constructor lets you specify both the preliminary potential and the same key value mappings.
InitialCapacity is set to hold enough space, along with all the mapping length of the map m, at the same time as loadFactor determines when the map should grow its ability.
There is a loadFactor of 0.75, which means that it will resize when you fill the current capacity to 75%
Setting the load factor can help optimise memory usage and control how often the map resizes.
Basic Operations on ConcurrentHashMap
ConcurrentHashMap in Java supports various basic operations for adding, updating, retrieving, and removing elements. Below are some commonly used operations along with explanations, examples, and executable code.
1. Inserting an Element (put())
The put() method adds a key-value pair to the map or updates the value if the key already exists.
Example
import java.util.concurrent.ConcurrentHashMap;
public class PutExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("Apple", 3);
map.put("Banana", 5);
// Updating the value for "Apple"
map.put("Apple", 4);
System.out.println("ConcurrentHashMap after inserting elements: " + map);
}
}
Output
ConcurrentHashMap after inserting elements: {Apple=4, Banana=5}
2. Retrieving an Element (get())
The get() method retrieves the value associated with a given key.
It returns the cost mapped to the specified key. If the key is not located, it can return null or a default cost the usage of getOrDefault().
Example:
import java.util.concurrent.ConcurrentHashMap;
public class GetExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("Apple", 3);
// Retrieving the value for "Apple"
int appleCount = map.get("Apple");
// Using getOrDefault to provide a default value
int orangeCount = map.getOrDefault("Orange", 0);
System.out.println("Apple count: " + appleCount);
System.out.println("Orange count: " + orangeCount);
}
}
Output
Apple count: 3
Orange count: 0
3. Removing an Element (remove())
The remove() method deletes a key-value pair from the map. The method removes the entry associated with the given key. If the key is not found, nothing happens.
Example:
import java.util.concurrent.ConcurrentHashMap;
public class RemoveExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("Apple", 3);
map.put("Banana", 5);
// Removing "Banana"
map.remove("Banana");
System.out.println("ConcurrentHashMap after removal: " + map);
}
}
Output:
ConcurrentHashMap after removal: {Apple=3}
4. Conditional Insertion (putIfAbsent())
The putIfAbsent() method adds a key-price pair only when the key is not available. This approach tests if the key remains absent inside the map earlier than inserting the value. If the key’s already present, it does not do anything.
Example:
import java.util.concurrent.ConcurrentHashMap;
public class PutIfAbsentExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("Apple", 3);
// Trying to add "Apple" again
map.putIfAbsent("Apple", 4);
// Adding "Orange"
map.putIfAbsent("Orange", 6);
System.out.println("ConcurrentHashMap after conditional insertion: " + map);
}
}
Output:
ConcurrentHashMap after conditional insertion: {Apple=3, Orange=6}
5. Replacing an Element (replace())
The replace() method updates the price for a specific key if the key is present. You can update the value that is associated with a given key if it exists. There is likewise a version that replaces the value if it matches a designated old price.
Example:
import java.util.concurrent.ConcurrentHashMap;
public class ReplaceExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("Apple", 3);
// Replacing the value for "Apple"
map.replace("Apple", 5);
System.out.println("ConcurrentHashMap after replacement: " + map);
}
}
Output:
ConcurrentHashMap after replacement: {Apple=5}
6. Checking if a Key Exists (containsKey())
The containsKey() method checks if a specific key is there or not in the map. It returns true if the map carries the given key, otherwise false.
Example:
import java.util.concurrent.ConcurrentHashMap;
public class ContainsKeyExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("Apple", 3);
// Checking if "Apple" is present
boolean hasApple = map.containsKey("Apple");
// Checking if "Banana" is present
boolean hasBanana = map.containsKey("Banana");
System.out.println("Is Apple present? " + hasApple);
System.out.println("Is Banana present? " + hasBanana);
}
}
Output:
Is Apple present? true
Is Banana present? false
7. Iterating Over the Map
The ConcurrentHashMap allows iterating over its elements using more suitable loops or iterators. You can use a for-each loop to iterate over the key-price pairs. The iterator is weakly constant, which means it displays the map’s state whilst the new release starts and may reflect some updates made to the map.
Example:
import java.util.concurrent.ConcurrentHashMap;
public class IterationExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("Apple", 3);
map.put("Banana", 5);
// Iterating over the map
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
}
}
Output:
Apple: 3
Banana: 5
These basic operations help you manage data effectively using ConcurrentHashMap, ensuring thread safety in concurrent programs.
Complexity of ConcurrentHashMap in Java
Operation
Average Time Complexity
Explanation
put()
O(1)
Efficient due to segmented structure.
get()
O(1)
Quick lookup using hash function.
remove()
O(1)
Fast deletion via direct bucket access.
containsKey()
O(1)
Constant time check for key existence.
putIfAbsent()
O(1)
Similar to put(), with extra check.
replace()
O(1)
Directly updates value for the given key.
Iteration (for-each loop)
O(n)
Linear time based on the map’s size.
ConcurrentHashMap vs Hashtable
Feature
ConcurrentHashMap
Hashtable
Thread Safety
Thread-safe with segment-level locking for better performance.
Thread-safe with a single lock for the entire map.
Locking Mechanism
Uses multiple locks (segment-based).
Uses a single lock for the entire map.
Null Keys/Values
Does not allow null keys or values.
Does not allow null keys or values.
Performance Under High Concurrency
Higher performance due to reduced contention.
Slower due to single lock, causing more contention.
Iterator Consistency
Weakly consistent iterator.
Fail-fast iterator that throws ConcurrentModificationException.
Introduced In
Java 1.5 (part of java.util.concurrent package).
Java 1.0 (java.util package).
Usage
Suitable for high-concurrency applications.
Suitable for low-concurrency environments.
Method Reference of ConcurrentHashMap
Method
Description
Parameters
Return Type
put(K key, V value)
Adds or updates a key-value pair.
key – Key, value – Value
V (previous value or null)
get(Object key)
Retrieves the value associated with the specified key.
key – Key
V
remove(Object key)
Removes the key-value pair for the specified key.
key – Key
V (removed value or null)
putIfAbsent(K key, V value)
Adds a key-value pair if the key is not already present.
key – Key, value – Value
V (previous value or null)
replace(K key, V oldValue, V newValue)
Replaces the value if the key is mapped to the specified old value.
key, oldValue, newValue
boolean
containsKey(Object key)
Checks if the map contains the specified key.
key – Key
boolean
containsValue(Object value)
Checks if the map contains the specified value.
value – Value
boolean
size()
Returns the number of key-value pairs in the map.
None
int
isEmpty()
Checks if the map is empty.
None
boolean
clear()
Removes all key-value pairs from the map.
None
void
computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
Computes the value if the key is absent, using the given function.
key, mappingFunction
V
computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
Computes a new value for the specified key if it’s present.
key, remappingFunction
V
merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
Merges the specified value with the existing one.
key, value, remappingFunction
V
keySet()
Returns a set view of the keys contained in the map.
None
Set<K>
values()
Returns a collection view of the values contained in the map.
None
Collection<V>
Advantages of ConcurrentHashMap
High Concurrency: Allows multiple threads to read and write simultaneously without blocking each other.
Segmented Locking: Reduces contention by locking only specific segments, not the entire map.
Thread Safety: Provides built-in thread-safe operations without external synchronisation.
Atomic Methods: Supports atomic operations like putIfAbsent(), remove(), and replace().
Weakly Consistent Iterators: Iterators can be used safely in multi-threaded environments without throwing exceptions.
Scalable Performance: Better performance compared to Hashtable in high-concurrency scenarios.
Disadvantages of ConcurrentHashMap
No Null Keys/Values: Does not support null as a key or value, which may limit use cases.
Weak Iterator Consistency: Iterators may not reflect the latest changes, which can lead to inconsistent views.
Memory Overhead: Requires more memory due to the internal segment structure.
Complex Locking Mechanism: The segmented locking can be harder to understand compared to simple synchronisation.
Limited Atomicity Guarantees: Only specific methods provide atomic operations, requiring careful use in some scenarios.
ConcurrentHashMap is a powerful tool for handling data in multi-threaded Java applications. Its segmented locking mechanism ensures that multiple threads can access and update the map concurrently, leading to higher performance in high-concurrency scenarios. This makes it a popular choice for applications that require frequent read-and-write operations.
While it offers many advantages, such as atomic methods and weakly consistent iterators, there are some limitations, like the inability to store null keys or values. Overall, ConcurrentHashMap strikes a good balance between thread safety and performance, making it a suitable choice for developers working with concurrent programming in Java. If you want to master Java, consider pursuing Hero Vired’s Certificate Program in Application Development.
FAQs
What is ConcurrentHashMap used for?
You can use the ConcurrentHashMap in order to perform any kind of thread-safe map operation in multi-thread environments. This will allow you to use multiple threads to access and alter the map simultaneously.
Can ConcurrentHashMap store null values?
No, it does not support null as either a key or a value. Attempting to add a null will throw a NullPointerException.
How does ConcurrentHashMap improve performance?
It uses segmented locking to reduce contention among threads, allowing better performance in high-concurrency scenarios compared to other thread-safe maps.
Is ConcurrentHashMap faster than Hashtable?
Yes, ConcurrentHashMap is commonly quicker due to its segmented locking mechanism, which reduces locking overhead as compared to the single lock used in Hashtable.
What is the time complexity of get() in ConcurrentHashMap?
The average time complexity is O(1), making it efficient for retrieving values based totally on keys.
How do you remove an element from ConcurrentHashMap?
You can eliminate an element with the help of the remove() method, passing the important thing of the element you need to delete.
What is the default concurrency stage in ConcurrentHashMap?
The default concurrency level is sixteen, meaning the map is split into 16 segments for managing concurrent get entry.
Hero Vired is a leading LearnTech company dedicated to offering cutting-edge programs in collaboration with top-tier global institutions. As part of the esteemed Hero Group, we are committed to revolutionizing the skill development landscape in India. Our programs, delivered by industry experts, are designed to empower professionals and students with the skills they need to thrive in today’s competitive job market.