In concurrent programming, Java provides thread-safe collection classes to handle shared data without compromising integrity or performance. The ConcurrentMap
interface and ConcurrentHashMap
class are vital for achieving thread safety in a concurrent environment.
1. ConcurrentMap Interface
The ConcurrentMap<K, V>
is part of the java.util.concurrent
package and extends the Map<K, V>
interface. It introduces atomic operations to modify the map concurrently.
Important Methods in ConcurrentMap:
V putIfAbsent(K key, V value)
: Puts the key-value pair only if the key is not already associated.boolean remove(Object key, Object value)
: Removes the key only if it’s mapped to the given value.boolean replace(K key, V oldValue, V newValue)
: Replaces the value for a key only if currently mapped tooldValue
.V replace(K key, V value)
: Replaces the value for the key unconditionally if present.
Features:
- Ensures atomicity and consistency during modifications.
- Thread-safe: can be accessed by multiple threads simultaneously without explicit synchronization.
 2. ConcurrentHashMap Class
ConcurrentHashMap<K, V>
is a thread-safe implementation of the ConcurrentMap
interface. It is part of java.util.concurrent
and is optimized for high-concurrency scenarios.
Important Characteristics:
- No null keys or values: Unlike
HashMap
, it does not allownull
keys or values. - Segmented locking (Java 7 and earlier): Internally divided into segments (buckets) to reduce lock contention.
- CAS (Compare-And-Swap) and synchronized blocks (Java 8+): Better performance through lock stripping and non-blocking algorithms.
- Constructors:
ConcurrentHashMap<>()
ConcurrentHashMap<>(int initialCapacity)
ConcurrentHashMap<>(int initialCapacity, float loadFactor)
ConcurrentHashMap<>(int initialCapacity, float loadFactor, int concurrencyLevel)
Code language: HTML, XML (xml)
Program-1
This Java program demonstrates the use of the ConcurrentMap
interface and its implementation using ConcurrentHashMap
to manage and manipulate a map of river names and their lengths in a thread-safe manner.
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class ConcurrentMapDemo { public static void main(String[] args) { ConcurrentMap<String, Integer> riverLengths = new ConcurrentHashMap<>(); riverLengths.putIfAbsent("Ganges", 2525); riverLengths.putIfAbsent("Yamuna", 1376); riverLengths.putIfAbsent("Brahmaputra", 2900); riverLengths.putIfAbsent("Godavari", 1465); riverLengths.putIfAbsent("Krishna", 1400); System.out.println("Initial river lengths: " + riverLengths); riverLengths.putIfAbsent("Ganges", 2500); System.out.println("After putIfAbsent with duplicate key: " + riverLengths); riverLengths.replace("Yamuna", 1376, 1370); System.out.println("After replace: " + riverLengths); riverLengths.remove("Godavari", 1465); System.out.println("After remove: " + riverLengths); // Demonstrate thread-safe updates Runnable task = () -> { for (int i = 0; i < 10; i++) { riverLengths.merge("Ganges", 10, Integer::sum); } }; // Create multiple threads to update the map Thread t1 = new Thread(task); Thread t2 = new Thread(task); Thread t3 = new Thread(task); t1.start(); t2.start(); t3.start(); try { t1.join(); t2.join(); t3.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Final river lengths after concurrent updates: " + riverLengths); } } /* C:\>javac ConcurrentMapDemo.java C:\>java ConcurrentMapDemo Initial river lengths: {Brahmaputra=2900, Ganges=2525, Krishna=1400, Yamuna=1376, Godavari=1465} After putIfAbsent with duplicate key: {Brahmaputra=2900, Ganges=2525, Krishna=1400, Yamuna=1376, Godavari=1465} After replace: {Brahmaputra=2900, Ganges=2525, Krishna=1400, Yamuna=1370, Godavari=1465} After remove: {Brahmaputra=2900, Ganges=2525, Krishna=1400, Yamuna=1370} Final river lengths after concurrent updates: {Brahmaputra=2900, Ganges=2825, Krishna=1400, Yamuna=1370} */
Program-2
This Java program illustrates the use of the ConcurrentMap
interface and the ConcurrentHashMap
class to simulate a thread-safe message-passing system between senders and recipients. It showcases concurrent operations where multiple threads simultaneously send and receive messages without causing data corruption or race conditions.
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class ConcurrentMessageSystem { private static final ConcurrentMap<String, String> messageQueue = new ConcurrentHashMap<>(); // Method to send a message public static void sendMessage(String recipient, String message) { messageQueue.put(recipient, message); System.out.println("Message sent to " + recipient + ": " + message); } // Method to receive a message public static String receiveMessage(String recipient) { String message = messageQueue.remove(recipient); if (message != null) { System.out.println("Message received by " + recipient + ": " + message); } else { System.out.println("No message for " + recipient); } return message; } public static void main(String[] args) { // Create multiple threads to send and receive messages concurrently Thread sender1 = new Thread(() -> sendMessage("Mahesh", "Hello Mahesh!")); Thread sender2 = new Thread(() -> sendMessage("Paani", "Hey Paani, how's it going?")); Thread receiver1 = new Thread(() -> receiveMessage("Mahesh")); Thread receiver2 = new Thread(() -> receiveMessage("Paani")); // Start threads sender1.start(); sender2.start(); receiver1.start(); receiver2.start(); // Wait for threads to finish try { sender1.join(); sender2.join(); receiver1.join(); receiver2.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } /* C:\>javac ConcurrentMessageSystem.java C:\>java ConcurrentMessageSystem Message received by Mahesh: Hello Mahesh! Message sent to Paani: Hey Paani, how's it going? Message received by Paani: Hey Paani, how's it going? Message sent to Mahesh: Hello Mahesh! */
Program-3
This Java program simulates a thread-safe ticket reservation system for darshan bookings. It handles multiple devotees trying to reserve limited tickets concurrently, ensuring that the reservation logic is atomic and race-condition-free using ConcurrentHashMap
and AtomicInteger
.
import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; public class DarshanReservationSystem { private static final int MAX_TICKETS = 3; private static final ConcurrentHashMap<String, Integer> ticketAvailability = new ConcurrentHashMap<>(); private static final AtomicInteger totalReservedTickets = new AtomicInteger(0); static { // Initialize ticket availability ticketAvailability.put("DarshanTicket", MAX_TICKETS); } public static boolean reserveTicket(String DevoteeId) { // Check if tickets are available if (totalReservedTickets.get() >= MAX_TICKETS) { System.out.println("Sorry, all tickets have been reserved. Please try again later."); return false; } // Reserve ticket int remainingTickets = ticketAvailability.getOrDefault("DarshanTicket", 0); if (remainingTickets > 0) { int updatedRemainingTickets = ticketAvailability.compute("DarshanTicket", (k, v) -> v - 1); if (updatedRemainingTickets >= 0) { totalReservedTickets.incrementAndGet(); System.out.println("Ticket reserved for Devotee: " + DevoteeId); return true; } } System.out.println("Sorry, failed to reserve ticket for Devotee: " + DevoteeId); return false; } public static void main(String[] args) { Random random = new Random(); for (int i = 1; i <= 5; i++) { String DevoteeId = "Devotee" + i; Thread thread = new Thread(() -> { // Introduce random delay try { Thread.sleep(random.nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } boolean success = reserveTicket(DevoteeId); if (!success) { System.out.println("Devotee " + DevoteeId + " could not reserve a ticket."); } }); thread.start(); } } } /* C:\>javac DarshanReservationSystem.java C:\>java DarshanReservationSystem Ticket reserved for Devotee: Devotee5 Ticket reserved for Devotee: Devotee4 Ticket reserved for Devotee: Devotee1 Sorry, all tickets have been reserved. Please try again later. Devotee Devotee3 could not reserve a ticket. Sorry, all tickets have been reserved. Please try again later. Devotee Devotee2 could not reserve a ticket. */
The DarshanReservationSystem
program efficiently models a concurrent reservation system where limited resources (tickets) are accessed by multiple clients (devotees). By combining ConcurrentHashMap
and AtomicInteger
, it maintains consistency, avoids overbooking, and provides a strong foundation for real-world ticketing logic.
The ConcurrentMap
interface and its primary implementation, ConcurrentHashMap
, provide powerful tools for building high-performance, thread-safe collections in concurrent Java applications. They are essential when multiple threads need to access and modify a shared map without risking data inconsistency or race conditions.