Also, Java 8 uses the compare-and-set primitive optimistically to place the initial heads in the table, which is very fast.
After the hash table expands, it never shrinks, possibly leading to a memory 'leak' after entries are removed.
A concurrent modification is supposed to be detected by this mechanism, throwing a java.util.ConcurrentModificationException,[3] but it is not guaranteed to occur in all cases and should not be relied on.
This is a partial solution, because it is still possible that the underlying Map can be inadvertently accessed by Threads which keep or obtain unwrapped references.
Context switches require from microseconds to milliseconds, while the Map's own basic operations normally take nanoseconds.
Modern JVMs will inline most of the lock code, reducing it to only a few instructions, keeping the no-contention case very fast.
Reentrant techniques like native synchronization or java.util.concurrent.ReentrantReadWriteLock however have extra performance-reducing baggage in the maintenance of the reentrancy depth, affecting the no-contention case as well.
The Convoy problem seems to be easing with modern JVMs, but it can be hidden by slow context switching: in this case, latency will increase, but throughput will continue to be acceptable.
Mutual exclusion solutions fail to take advantage of all of the computing power of a multiple-core system, because only one Thread is allowed inside the Map code at a time.
The implementations of the particular concurrent Maps provided by the Java Collections Framework and others sometimes take advantage of multiple cores using lock free programming techniques.
Lock-free techniques use operations like the compareAndSet() intrinsic method available on many of the Java classes such as AtomicReference to do conditional updates of some Map-internal structures atomically.
The techniques are complex, relying often on the rules of inter-thread communication provided by volatile variables, the happens-before relation, special kinds of lock-free 'retry loops' (which are not like spin locks in that they always produce progress).
The diagram indicates how synchronizing using Collections.synchronizedMap(java.util.Map)wrapping a regular HashMap (purple) may not scale as well as ConcurrentHashMap (red).
(The flat spots may be rehashes producing tables that are bigger than the Nursery, and ConcurrentHashMap takes more space.
GC and JVM process expansion change the curves considerably, and some internal lock-Free techniques generate garbage on contention.
Yet another problem with mutual exclusion approaches is that the assumption of complete atomicity made by some single-threaded code creates sporadic unacceptably long inter-Thread delays in a concurrent environment.
For example, a multi-threaded web server cannot allow some responses to be delayed by long-running iterations of other threads executing other requests that are searching for a particular value.
For example, if we want to multiply a value in the Map by a constant C atomically: The putIfAbsent(k, v) is also useful when the entry for the key is allowed to be absent.
The Java collections framework was designed and developed primarily by Joshua Bloch, and was introduced in JDK 1.2.