The ConcurrentHashMap
is a class in Java that implements the ConcurrentMap
interface. It is part of the Java Collection Framework and extends the AbstractMap
class.
ConcurrentHashMap
is thread-safe, which means it is designed to support high concurrency levels by handling multiple threads concurrently without any inconsistencies. It allows multiple threads to perform retrieve
(get
) and update
(insert
& delete
) operations. Internally, ConcurrentHashMap
uses concepts of Segmentation to store data which allows higher degree of concurrency.
Here is an example of how to use ConcurrentHashMap
in Java:
package org.kodejava.util;
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
// Create a ConcurrentHashMap instance
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// Add elements
map.put("One", 1);
map.put("Two", 2);
map.put("Three", 3);
// Retrieve elements
Integer one = map.get("One");
System.out.println("Retrieved value for 'One': " + one);
// Remove an element
map.remove("Two");
// Print all elements
map.forEach((key, value) -> System.out.println(key + " = " + value));
}
}
Output:
Retrieved value for 'One': 1
One = 1
Three = 3
In this example, we’re creating a ConcurrentHashMap
, adding some elements to it, retrieving an element, removing an element, and finally printing all the elements.
One thing to note is that while ConcurrentHashMap
allows multiple threads to read and write concurrently, a get()
operation might not reflect the latest put()
operation, since it might be looking at a previous segment. Further thread synchronization mechanisms might be necessary depending on your exact use case.
Also, worth mentioning, null
values and null
keys are not permitted in ConcurrentHashMap
to prevent ambiguities and potential errors in multithreaded contexts. If you try to use null
, ConcurrentHashMap
will throw a NullPointerException
.
Here’s an example demonstrating the usage of ConcurrentHashMap
in a multithreaded context:
package org.kodejava.util;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ConcurrentHashMapThreadDemo {
public static void main(String[] args) throws InterruptedException {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// Create a ThreadPool with 5 threads
try (ExecutorService executor = Executors.newFixedThreadPool(5)) {
// Runnable task to increment a value in the map
Runnable task = () -> {
for (int i = 0; i < 10; i++) {
map.compute("TestKey", (key, value) -> {
if (value == null) {
return 1;
} else {
return value + 1;
}
});
}
};
// Submit the task to each thread in the pool
for (int i = 0; i < 5; i++) {
executor.submit(task);
}
// Shut down the executor and wait for tasks to complete
executor.shutdown();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
}
System.out.println("Final value for 'TestKey': " + map.get("TestKey"));
}
}
Output:
Final value for 'TestKey': 50
In this example, we’re creating a ConcurrentHashMap
and a thread pool with ExecutorService
. We’re then defining a Runnable
task, which increments the value of the “TestKey” key in the map 10 times.
The task uses ConcurrentHashMap
‘s compute()
method, which is atomic, meaning that the retrieval and update of the value is done as a single operation that cannot be interleaved with other operations. We then submit the task to each of the five threads in our thread pool. After all threads have completed their tasks, we retrieve and print the final value of “TestKey”.
If everything works correctly, the output should be “Final value for ‘TestKey’: 50”, because we have 5 threads each incrementing the value 10 times. This demonstrates the thread-safety of ConcurrentHashMap
, as the compute()
operation is done atomically and many threads were able to modify the map simultaneously without causing inconsistencies. If we were using a plain HashMap
instead, we could not guarantee this would be the case.