Java ConcurrentHashMap Methods Tutorial with Examples

ConcurrentHashMap is a part of the Java Collections Framework and provides a thread-safe implementation of the Map interface. It is designed for high concurrency and allows concurrent read and write operations without blocking. This tutorial will cover all methods of ConcurrentHashMap with examples and outputs, highlighting key points, use cases, best practices, performance considerations, and a real-time example with CRUD operations.

Table of Contents

  1. Introduction
  2. Key Points
  3. ConcurrentHashMap Methods
    • put()
    • putAll()
    • get()
    • remove()
    • clear()
    • size()
    • isEmpty()
    • containsKey()
    • containsValue()
    • keySet()
    • values()
    • entrySet()
    • forEach()
    • replace()
    • compute()
    • computeIfAbsent()
    • computeIfPresent()
    • merge()
  4. Use Cases
  5. Best Practices
  6. Performance Considerations
  7. Real-time Example with CRUD Operations
  8. Conclusion

1. Introduction

A ConcurrentHashMap in Java is a part of the Java Collections Framework and provides a way to manage key-value pairs in a thread-safe manner. It is found in the java.util.concurrent package and is designed specifically for use in concurrent applications where high concurrency is required.

2. Key Points

  • ConcurrentHashMap does not allow null keys or null values.
  • It is designed for high concurrency, allowing multiple threads to read and write without blocking.
  • It provides thread-safe operations without the need for explicit synchronization.
  • It uses a segmented locking mechanism to achieve concurrency.

3. ConcurrentHashMap Methods

3.1. put()

The put() method is used to insert key-value pairs into the ConcurrentHashMap.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        System.out.println(fruits);
    }
}

Output:

{Apple=50, Banana=30, Mango=20}

3.2. putAll()

The putAll() method adds all key-value pairs from another map to the ConcurrentHashMap.

Example:

import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);

        Map<String, Integer> moreFruits = new ConcurrentHashMap<>();
        moreFruits.put("Mango", 20);
        moreFruits.put("Orange", 40);

        fruits.putAll(moreFruits);
        System.out.println(fruits);
    }
}

Output:

{Apple=50, Banana=30, Mango=20, Orange=40}

3.3. get()

The get() method retrieves the value associated with the specified key.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        System.out.println(fruits.get("Banana")); // 30
    }
}

Output:

30

3.4. remove()

The remove() method removes the key-value pair associated with the specified key.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        fruits.remove("Banana");
        System.out.println(fruits); // {Apple=50, Mango=20}
    }
}

Output:

{Apple=50, Mango=20}

3.5. clear()

The clear() method removes all key-value pairs from the ConcurrentHashMap.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        fruits.clear();
        System.out.println(fruits); // {}
    }
}

Output:

{}

3.6. size()

The size() method returns the number of key-value pairs in the ConcurrentHashMap.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        System.out.println(fruits.size()); // 3
    }
}

Output:

3

3.7. isEmpty()

The isEmpty() method checks if the ConcurrentHashMap is empty.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        System.out.println(fruits.isEmpty()); // true
        fruits.put("Apple", 50);
        System.out.println(fruits.isEmpty()); // false
    }
}

Output:

true
false

3.8. containsKey()

The containsKey() method checks if the ConcurrentHashMap contains a specified key.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        System.out.println(fruits.containsKey("Banana")); // true
        System.out.println(fruits.containsKey("Mango")); // false
    }
}

Output:

true
false

3.9. containsValue()

The containsValue() method checks if the ConcurrentHashMap contains a specified value.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        System.out.println(fruits.containsValue(30)); // true
        System.out.println(fruits.containsValue(20)); // false
    }
}

Output:

true
false

3.10. keySet()

The keySet() method returns a set view of the keys contained in the ConcurrentHashMap.

Example:

import java.util.concurrent.ConcurrentHashMap;
import java.util.Set;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        Set<String> keys = fruits.keySet();
        System.out.println(keys); // [Apple, Banana, Mango]
    }
}

Output:

[Apple, Banana, Mango]

3.11. values()

The values() method returns a collection view of the values contained in the ConcurrentHashMap.

Example:

import java.util.concurrent.ConcurrentHashMap;
import java.util.Collection;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        Collection<Integer> values = fruits.values();
        System.out.println(values); // [50, 30, 20]
    }
}

Output:

[50, 30, 20]

3.12. entrySet()

The entrySet() method returns a set view of the mappings contained in the ConcurrentHashMap.

Example:

import java.util.concurrent.ConcurrentHashMap;
import java.util.Set;
import java.util.Map.Entry;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        Set<Entry<String, Integer



>> entries = fruits.entrySet();
        for (Entry<String, Integer> entry : entries) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

Output:

Apple = 50
Banana = 30
Mango = 20

3.13. forEach()

The forEach() method performs the given action for each entry in the ConcurrentHashMap.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        fruits.forEach((key, value) -> System.out.println(key + " = " + value));
    }
}

Output:

Apple = 50
Banana = 30
Mango = 20

3.14. replace()

The replace() method replaces the entry for the specified key only if it is currently mapped to some value.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.replace("Banana", 40);
        System.out.println(fruits); // {Apple=50, Banana=40, Mango=20}
    }
}

Output:

{Apple=50, Banana=40, Mango=20}

3.15. compute()

The compute() method computes a new mapping for the specified key and its current mapped value (or null if there is no current mapping).

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.compute("Banana", (key, value) -> (value == null) ? 40 : value + 10);
        System.out.println(fruits); // {Apple=50, Banana=40, Mango=20}
    }
}

Output:

{Apple=50, Banana=40, Mango=20}

3.16. computeIfAbsent()

The computeIfAbsent() method computes a mapping for the specified key if it is not already present.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.computeIfAbsent("Mango", key -> 20);
        System.out.println(fruits); // {Apple=50, Banana=30, Mango=20}
    }
}

Output:

{Apple=50, Banana=30, Mango=20}

3.17. computeIfPresent()

The computeIfPresent() method computes a new mapping for the specified key if it is currently present.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.computeIfPresent("Banana", (key, value) -> value + 10);
        System.out.println(fruits); // {Apple=50, Banana=40, Mango=20}
    }
}

Output:

{Apple=50, Banana=40, Mango=20}

3.18. merge()

The merge() method merges the specified value with the existing value associated with the specified key.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> fruits = new ConcurrentHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.merge("Banana", 20, (oldValue, newValue) -> oldValue + newValue);
        System.out.println(fruits); // {Apple=50, Banana=50, Mango=20}
    }
}

Output:

{Apple=50, Banana=50, Mango=20}

4. Use Cases

  • Caching: Storing key-value pairs in a thread-safe manner.
  • Concurrent applications: Managing shared data in multi-threaded applications.
  • Real-time data processing: Handling high concurrency scenarios in real-time data processing systems.

5. Best Practices

  • Use appropriate initial capacity: If the size of the map is known in advance, setting an initial capacity can improve performance.
  • Avoid frequent resizing: Adding elements frequently can cause resizing. Consider setting an appropriate initial capacity.
  • Thread safety: Utilize the built-in thread safety features of ConcurrentHashMap without additional synchronization.

6. Performance Considerations

  • High concurrency: ConcurrentHashMap is designed for high concurrency, allowing multiple threads to read and write without blocking.
  • Segmented locking: Uses segmented locking to achieve thread safety, providing better performance compared to synchronized collections.
  • Memory usage: Each entry in a ConcurrentHashMap requires additional memory for storing hash codes and pointers.

7. Real-time Example with CRUD Operations

Managing a Product Inventory:

Product.java:

public class Product {
    private String name;
    private int quantity;

    public Product(String name, int quantity) {
        this.name = name;
        this.quantity = quantity;
    }

    public String getName() {
        return name;
    }

    public int getQuantity() {
        return quantity;
    }

    @Override
    public String toString() {
        return "Product{name='" + name + "', quantity=" + quantity + "}";
    }
}

Main.java:

import java.util.concurrent.ConcurrentHashMap;

public class Main {
    public static void main(String[] args) {
        ConcurrentHashMap<Integer, Product> productInventory = new ConcurrentHashMap<>();

        // Create
        productInventory.put(1, new Product("Laptop", 10));
        productInventory.put(2, new Product("Mobile", 20));
        productInventory.put(3, new Product("Tablet", 15));

        // Read
        for (ConcurrentHashMap.Entry<Integer, Product> entry : productInventory.entrySet()) {
            System.out.println("Product ID: " + entry.getKey() + ", Product: " + entry.getValue());
        }

        // Update
        productInventory.put(2, new Product("Mobile", 25));
        System.out.println("After Update:");
        for (ConcurrentHashMap.Entry<Integer, Product> entry : productInventory.entrySet()) {
            System.out.println("Product ID: " + entry.getKey() + ", Product: " + entry.getValue());
        }

        // Delete
        productInventory.remove(1);
        System.out.println("After Deletion:");
        for (ConcurrentHashMap.Entry<Integer, Product> entry : productInventory.entrySet()) {
            System.out.println("Product ID: " + entry.getKey() + ", Product: " + entry.getValue());
        }
    }
}

Output:

Product ID: 1, Product: Product{name='Laptop', quantity=10}
Product ID: 2, Product: Product{name='Mobile', quantity=20}
Product ID: 3, Product: Product{name='Tablet', quantity=15}
After Update:
Product ID: 2, Product: Product{name='Mobile', quantity=25}
Product ID: 3, Product: Product{name='Tablet', quantity=15}
After Deletion:
Product ID: 2, Product: Product{name='Mobile', quantity=25}
Product ID: 3, Product: Product{name='Tablet', quantity=15}

8. Conclusion

The ConcurrentHashMap class in Java is a powerful class for managing key-value pairs in a thread-safe manner. By understanding its methods, use cases, and best practices, you can effectively utilize ConcurrentHashMap in your Java applications. This tutorial covers the essential methods with examples and demonstrates a real-time example with CRUD operations.

Comments