Detailed explanation
HashMap, Hashtable, and ConcurrentHashMap implement Map, but differ in concurrency guarantees, null handling, and iteration behaviour. HashMap is unsynchronized and permits one null key and multiple null values. It is normally the right choice for local data or data protected by an external lock. Calling it “fast” is contextual: it avoids synchronization overhead, but concurrent modification without proper coordination can cause races and inconsistent results. All three offer expected constant-time basic lookups with well-distributed hashes; none guarantees iteration order.
Hashtable is a legacy thread-safe implementation that rejects null keys and values. Its core operations synchronize on the table instance, so threads accessing the same table contend for a shared monitor. This protects individual operations, not arbitrary sequences of calls: checking containsKey and then calling put is not automatically one atomic action. Such a sequence needs a suitable atomic operation or external synchronization followed consistently by every participating thread. Hashtable remains relevant when reading older code, but it is generally not the preferred choice for new concurrent applications.
ConcurrentHashMap is designed for concurrent access and also rejects null keys and values. In modern Java implementations, retrievals generally do not acquire locks; updates combine compare-and-set operations with synchronization around affected bins when necessary. Describing it simply as “segmented locking” is outdated: that describes older implementations, notably Java 7, rather than Java 8 and later. Its concurrency design allows many operations on different parts of the map to proceed independently. A completed update for a key has a happens-before relationship with a subsequent non-null retrieval reporting that updated value.
In interviews, explain operation-level safety as well as API differences. Prefer putIfAbsent, compute, or merge over separate read-modify-write steps when atomic per-key changes are required. ConcurrentHashMap iterators are weakly consistent: they tolerate concurrent updates without ConcurrentModificationException, but do not provide a snapshot. HashMap and Hashtable collection-view iterators are fail-fast on a best-effort basis. Finally, a concurrent map does not make mutable values thread-safe, and its size during updates should not drive correctness-sensitive decisions.
Key points to remember
- HashMap: unsynchronized; allows one null key and multiple null values.
- Hashtable: legacy; core operations use table-wide synchronization; rejects nulls.
- ConcurrentHashMap: thread-safe; rejects nulls; generally preferred for shared concurrent maps.
- Modern ConcurrentHashMap uses CAS and bin-level synchronization, not the older fixed-segment design.
- Atomic map operations protect specific updates, not entire workflows or mutable value objects.
Common mistakes candidates make
- Claiming that modern ConcurrentHashMap always uses segmented locking or locks every read.
- Assuming thread-safe get and put calls make a combined read-modify-write operation atomic.
- Treating fail-fast iterators as a concurrency guarantee or weakly consistent iterators as snapshots.
Likely follow-up questions
How would you update a shared counter stored in ConcurrentHashMap?
For a ConcurrentHashMap<String, Integer>, use counts.merge(key, 1, Integer::sum) to perform an atomic per-key increment. A separate get followed by put can lose updates when multiple threads increment simultaneously.
Why does ConcurrentHashMap reject null values?
Rejecting null makes a null result from get unambiguously mean that no mapping was observed. Allowing null would require distinguishing absence from a mapped null, and a separate containsKey check could race with concurrent updates.
How does Collections.synchronizedMap compare with ConcurrentHashMap?
Collections.synchronizedMap wraps a map and serializes access through a shared lock; iteration requires manually synchronizing on the returned wrapper. ConcurrentHashMap supports greater concurrent access and weakly consistent iteration without that external iteration lock.
Interview tip: Compare thread safety, null handling, and iteration first, then demonstrate practical understanding with one atomic-update example.
