Maps are often used in high-performance server applicationsfor example, as cache implementationsso a high-throughput thread-safe map implementation is an essential part of the Java platform. This requirement cannot be met by synchronized maps such as those provided by Collections.synchronizedMap, because with full synchronization each operation needs to obtain an exclusive lock on the entire map, effectively serializing access to it. Locking only a part of the collection at a timelock stripingcan achieve very large gains in throughput, as we shall see shortly with ConcurrentHashMap. But because there is no single lock for a client to hold to gain exclusive access, client-side locking no longer works, and clients need assistance from the collection itself to carry out atomic actions.
V putIfAbsent(K key, V value) // associate key with value only if key is not currently present. // return the old value (may be null) if the key was present, // otherwise return null boolean remove(Object key, Object value) // remove key only if it is currently mapped to value. Returns // true if the value was removed, false otherwise V replace(K key, V value) // replace entry for key only if it is currently present. Return // the old value (may be null) if the key was present, otherwise // return null boolean replace(K key, V oldValue, V newValue) // replace entry for key only if it is currently mapped to oldValue. // return true if the value was replaced, false otherwise
ConcurrentHashMap provides an implementation of ConcurrentMap and offers a highly effective solution to the problem of reconciling throughput with thread safety. It is optimized for reading, so retrievals do not block even while the table is being updated (to allow for this, the contract states that the results of retrievals will reflect the latest update operations completed before the start of the retrieval). Updates also can often proceed without blocking, because a ConcurrentHashMap consists of not one but a set of tables, called segments, each of which can be independently locked. If the number of segments is large enough relative to the number of threads accessing the table, there will often be no more than one update in progress per segment at any time. The constructors for ConcurrentHashMap are similar to those of HashMap, but with an extra one that provides the programmer with control over the number of segments that the map will use (its concurrency level):
ConcurrentHashMap() ConcurrentHashMap(int initialCapacity) ConcurrentHashMap(int initialCapacity, float loadFactor) ConcurrentHashMap( int initialCapacity, float loadFactor, int concurrencyLevel) ConcurrentHashMap(Map<? extends K,? extends V> m)
The class ConcurrentHashMap is a useful implementation of Map in any application where it is not necessary to lock the entire table; this is the one capability of SynchronizedMap which it does not support. That can sometimes present problems: for example, the size method attempts to count the entries in the map without using locks. If the map is being concurrently updated, however, the size method will not succeed in obtaining a consistent result. In this situation, it obtains exclusive access to the map by locking all the segments, obtaining the entry count from each, then unlocking them again. The performance cost involved in this is a justifiable tradeoff against the highly optimized performance for common operations, especially reads. Overall, ConcurrentHashMap is indispensable in highly concurrent contexts, where it performs far better than any available alternative.