Hashtable vs ConcurrentHashMap in Java: A Deep Dive

 

Hashtable vs ConcurrentHashMap in Java: A Deep Dive

In Java, working with key-value pairs efficiently is essential for building scalable and thread-safe applications. Two commonly discussed classes in this realm are Hashtable and ConcurrentHashMap. Though both are designed to work in multi-threaded environments, they differ significantly in design, performance, and behavior.

In this blog post, we'll explore these two classes in depth, understand their key differences, use cases, and make an informed decision on when to use which.


1. Introduction to Hashtable

What is Hashtable?

Hashtable is a legacy class in Java that implements the Map interface and provides a thread-safe way to store key-value pairs. It was part of the original version of Java, even before the Collections framework was introduced in Java 1.2.

Key Characteristics:

  • Synchronized methods for thread safety.

  • Does not allow null keys or null values.

  • Slower performance due to method-level synchronization.

  • Iterators are fail-fast and throw ConcurrentModificationException if modified concurrently.

Example Usage:

import java.util.Hashtable;

public class HashtableExample {
    public static void main(String[] args) {
        Hashtable<Integer, String> table = new Hashtable<>();
        table.put(1, "Apple");
        table.put(2, "Banana");

        System.out.println("Value for key 1: " + table.get(1));
    }
}

2. Introduction to ConcurrentHashMap

What is ConcurrentHashMap?

Introduced in Java 5 as part of the java.util.concurrent package, ConcurrentHashMap is designed to offer highly scalable and thread-safe operations without locking the entire map.

Key Characteristics:

  • Implements ConcurrentMap and Map interfaces.

  • Allows concurrent read and concurrent write with minimal locking.

  • Allows null values neither as key nor as value.

  • Uses bucket-level locking (Segmented locking) or CAS-based techniques (depending on Java version).

  • Iterators are weakly consistent — they reflect some, but not necessarily all, updates.

Example Usage:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>();
        map.put(1, "Red");
        map.put(2, "Blue");

        System.out.println("Value for key 2: " + map.get(2));
    }
}

3. Key Differences Between Hashtable and ConcurrentHashMap

Feature Hashtable ConcurrentHashMap
Thread Safety Thread-safe via synchronized methods Thread-safe via fine-grained locking
Performance Poor in high concurrency due to global lock Superior due to segmented locking
Null Keys/Values Neither key nor value can be null Same – neither key nor value can be null
Iterator Fail-fast Weakly consistent
Lock Granularity Locks entire map for every operation Locks at bucket level or per segment
Legacy vs Modern Legacy class, part of Java 1.0 Modern, introduced in Java 5
Usage in New Code Discouraged Recommended for concurrent scenarios

Why null is Not Allowed?

Neither Hashtable nor ConcurrentHashMap allow null keys or values. Why?

  • Hashtable: This design is historical.

  • ConcurrentHashMap: The main reason is to avoid ambiguity — a null return from get(key) could mean either the key is absent or explicitly mapped to null.


Thread Safety: How Do They Differ?

Hashtable:

public synchronized V put(K key, V value) {
    // synchronized on the entire table
}
  • Every operation is synchronized on the entire map.

  • Causes contention and reduced performance in multithreaded applications.

ConcurrentHashMap:

  • Uses bucket-level locking (Java 7 and earlier).

  • Uses lock-free reads and CAS (Compare-And-Swap) in Java 8 and above.

  • Multiple threads can read and write concurrently without blocking each other unnecessarily.


Performance Comparison

Hashtable:

  • Locking entire map for each operation results in serialization of threads.

  • Suitable only for very small datasets or when minimal concurrency is expected.

ConcurrentHashMap:

  • Designed for high concurrency.

  • Efficient for both read and write operations in multi-threaded environments.

  • Often used in real-time data processing applications, caching, and distributed systems.


Code Example: Comparing Thread Performance

import java.util.Hashtable;
import java.util.concurrent.*;

public class MapPerformanceTest {
    public static void main(String[] args) throws InterruptedException {
        Hashtable<Integer, Integer> hashtable = new Hashtable<>();
        ConcurrentHashMap<Integer, Integer> concurrentMap = new ConcurrentHashMap<>();

        ExecutorService executor = Executors.newFixedThreadPool(10);

        Runnable hashtableTask = () -> {
            for (int i = 0; i < 1000; i++) {
                hashtable.put(i, i);
            }
        };

        Runnable concurrentMapTask = () -> {
            for (int i = 0; i < 1000; i++) {
                concurrentMap.put(i, i);
            }
        };

        long start = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) executor.execute(hashtableTask);
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
        long end = System.currentTimeMillis();
        System.out.println("Hashtable time: " + (end - start) + " ms");

        executor = Executors.newFixedThreadPool(10);
        start = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) executor.execute(concurrentMapTask);
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
        end = System.currentTimeMillis();
        System.out.println("ConcurrentHashMap time: " + (end - start) + " ms");
    }
}

When Should You Use What?

 Use ConcurrentHashMap when:

  • You are developing high-performance, multi-threaded applications.

  • Your application has frequent concurrent reads/writes.

  • You are building scalable APIs or real-time data pipelines.

Avoid Hashtable unless:

  • You are maintaining legacy code.

  • You specifically need the synchronized behavior and can't use newer alternatives.

  • No concurrency is involved and thread safety is not critical.


Conclusion

Although both Hashtable and ConcurrentHashMap are thread-safe, their internal implementations and performance differ drastically. ConcurrentHashMap is the go-to choice for modern concurrent applications due to its non-blocking algorithms and superior throughput under load.

Use Case Recommendation
High-performance concurrent access       ConcurrentHashMap
Legacy application maintenance       Hashtable (with caution)
Null key/value support needed      Neither (use HashMap if thread safety isn’t required)


Previous
Next Post »