Java Program to Use TreeMap in Multithreaded Applications Using Synchronization
Below is the code implementation to use TreeMap in multithreaded applications and avoid race conditions.
1. Using Locks for Thread-Safe TreeMap
The main issue with utilizing TreeMap in a multithreaded context is the potential for race situations when many threads attempt to edit the map at the same time. Locks are one way to get around this.
Java
// Java program to Demonstrate Thread-Safe // TreeMap Using ReadWriteLock import java.util.Map; import java.util.TreeMap; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; // Driver Class public class ThreadSafeTreeMapExample { // ReadWriteLock for synchronization private final ReadWriteLock lock = new ReentrantReadWriteLock(); // TreeMap to store key-value pairs private final Map<String, Integer> threadSafeTreeMap = new TreeMap<>(); // Method to add key-value pairs to the TreeMap public void addToMap(String key, int value) { // Acquire write lock lock.writeLock().lock(); try { // Add key-value pair threadSafeTreeMap.put(key, value); System.out.println( "Added: " + key + ", " + value); } finally { // Release write lock lock.writeLock().unlock(); } } // Method to get value for a given key from the TreeMap public int getFromMap(String key) { // Acquire read lock lock.readLock().lock(); try { // Get value for key or return default value (-1) return threadSafeTreeMap.getOrDefault(key, - 1 ); } finally { // Release read lock lock.readLock().unlock(); } } // Main Function public static void main(String[] args) { ThreadSafeTreeMapExample example = new ThreadSafeTreeMapExample(); // Example usage: add key-value pairs in separate threads new Thread(() -> example.addToMap( "A" , 1 )).start(); new Thread(() -> example.addToMap( "B" , 2 )).start(); // Display values for keys "A" and "B" System.out.println( "Value for A: " + example.getFromMap( "A" )); System.out.println( "Value for B: " + example.getFromMap( "B" )); } } |
Added: A, 1 Added: B, 2 Value for A: 1 Value for B: 2
Explanation of the above Program:
- We have used a
ReadWriteLock
for synchronization to allow multiple threads to read simultaneously while ensuring exclusive write access. - Then, the
addToMap()
method adds key-value pairs to theTreeMap
while holding the write lock. - After that, the
getFromMap()
method retrieves the value for a given key from theTreeMap
while holding the read lock. - The
main
method demonstrates the usage of theThreadSafeTreeMapExample
class by adding key-value pairs in separate threads and then retrieving their values.
2. Using ConcurrentHashMap with TreeMap
Combining a ConcurrentHashMap with a TreeMap is an additional strategy. This leverages ConcurrentHashMap’s concurrent writing capabilities while enabling thread-safe read operations on the TreeMap.
Java
// Java Program to Utilize of TreeMap // in Concurrent Java Applications // Using ConcurrentHashMap with TreeMap import java.util.concurrent.*; import java.util.concurrent.locks.*; // Driver Class public class ConcurrentMapWithTreeMapExample { // ConcurrentSkipListMap for concurrent access private final ConcurrentSkipListMap<String, Integer> concurrentMap = new ConcurrentSkipListMap<>(); // ExecutorService for asynchronous execution private final ExecutorService executorService = Executors.newFixedThreadPool( 2 ); // Method to add key-value pair to the concurrent map // asynchronously public void addToMap(String key, int value) { CompletableFuture.runAsync(() -> { addEntryToMap(key, value); }, executorService); } // Method to get value for a given key from the // concurrent map public int getFromMap(String key) { return concurrentMap.getOrDefault(key, - 1 ); } // Method to get an ordered copy of the concurrent map public ConcurrentSkipListMap<String, Integer> getOrderedMap() { return new ConcurrentSkipListMap<>(concurrentMap); } // Private method to add entry to the concurrent map private void addEntryToMap(String key, int value) { concurrentMap.put(key, value); System.out.println( "Added: " + key + ", " + value); } // Main Function public static void main(String[] args) { ConcurrentMapWithTreeMapExample example = new ConcurrentMapWithTreeMapExample(); // Add key-value pairs asynchronously CompletableFuture<Void> futureA = CompletableFuture.runAsync(() -> example.addToMap( "A" , 1 ), example.executorService); CompletableFuture<Void> futureB = CompletableFuture.runAsync(() -> example.addToMap( "B" , 2 ), example.executorService); // Wait for all tasks to complete CompletableFuture.allOf(futureA, futureB).join(); // Display values for keys "A" and "B" System.out.println( "Value for A: " + example.getFromMap( "A" )); System.out.println( "Value for B: " + example.getFromMap( "B" )); // Get an ordered copy of the concurrent map ConcurrentSkipListMap<String, Integer> orderedMap = example.getOrderedMap(); System.out.println( "Ordered Map: " + orderedMap); // Shut down the executor service try { example.executorService.shutdown(); } finally { } } } |
Value for A: 1 Value for B: 2 Ordered Map: {A=1, B=2} Added: B, 2 Added: A, 1
Explanation of the above Program:
We have used the
ConcurrentSkipListMap
that allows concurrent access to the map.ExecutorService
with a fixed thread pool size of 2 is used for asynchronous execution of tasks.- The
addToMap
method adds key-value pairs to the map asynchronously usingCompletableFuture.runAsync
. - The
getFromMap
method retrieves the value for a given key from the concurrent map. - The
getOrderedMap
method returns an ordered copy of the concurrent map. - In the
main
method, key-value pairs are added asynchronously, and their values are displayed. An ordered copy of the map is also obtained and displayed. Finally, the executor service is shut down.
Effective Utilization of TreeMap in Concurrent Java Applications
A Java application may run many threads concurrently thanks to multithreading. Thread safety must be guaranteed when utilizing data structures like TreeMap in a multithreaded environment to prevent race situations. The recommended techniques for using TreeMap in multithreaded applications and avoiding race situations are covered in this tutorial.
TreeMap in a Multithreaded Environment
Thread safety is not inherent to TreeMap. Multiple threads altering a TreeMap concurrently may result in race situations and unexpected behavior. You may deal with this by using thread-safe alternatives such as ConcurrentNavigableMap, which is part of the java.util.concurrent package, or by using synchronization techniques.
Best Practices
- Synchronization: To manage access to TreeMap, use appropriate synchronization techniques.
- Thread-safe Alternatives: For concurrent access, take into account using thread-safe alternatives such as ConcurrentNavigableMap.
- Immutable Objects: To prevent problems with data mutation, if at all feasible, utilize immutable objects within the TreeMap.