Summary
Clarify that ConcurrentHashMap compute methods mapping functions execute at most once
Problem
The ConcurrentHashMap compute* methods are insufficiently clear
Solution
Clarify mutual exclusion behavior of mapping methods.
Specification
@@ 1656,33 +1656,36 @@
/**
* If the specified key is not already associated with a value,
* attempts to compute its value using the given mapping function
* and enters it into this map unless {@code null}. The entire
 * method invocation is performed atomically, so the function is
 * applied at most once per key. Some attempted update operations
 * on this map by other threads may be blocked while computation
 * is in progress, so the computation should be short and simple,
 * and must not attempt to update any other mappings of this map.
+ * method invocation is performed atomically. The supplied
+ * function is invoked exactly once per invocation of this method
+ * if the key is absent, else not at all. Some attempted update
+ * operations on this map by other threads may be blocked while
+ * computation is in progress, so the computation should be short
+ * and simple.
+ *
+ * <p>The mapping function must not modify this map during computation.
*
* @param key key with which the specified value is to be associated
* @param mappingFunction the function to compute a value
* @return the current (existing or computed) value associated with
* the specified key, or null if the computed value is null
* @throws NullPointerException if the specified key or mappingFunction
* is null
* @throws IllegalStateException if the computation detectably
* attempts a recursive update to this map that would
* otherwise never complete
* @throws RuntimeException or Error if the mappingFunction does so,
* in which case the mapping is left unestablished
*/
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
@@ 1767,32 +1770,35 @@
/**
* If the value for the specified key is present, attempts to
* compute a new mapping given the key and its current mapped
* value. The entire method invocation is performed atomically.
 * Some attempted update operations on this map by other threads
 * may be blocked while computation is in progress, so the
 * computation should be short and simple, and must not attempt to
 * update any other mappings of this map.
+ * The supplied function is invoked exactly once per invocation of
+ * this method if the key is present, else not at all. Some
+ * attempted update operations on this map by other threads may be
+ * blocked while computation is in progress, so the computation
+ * should be short and simple.
+ *
+ * <p>The remapping function must not modify this map during computation.
*
* @param key key with which a value may be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or remappingFunction
* is null
* @throws IllegalStateException if the computation detectably
* attempts a recursive update to this map that would
* otherwise never complete
* @throws RuntimeException or Error if the remappingFunction does so,
* in which case the mapping is unchanged
*/
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
if (key == null  remappingFunction == null)
@@ 1859,32 +1865,34 @@
/**
* Attempts to compute a mapping for the specified key and its
* current mapped value (or {@code null} if there is no current
* mapping). The entire method invocation is performed atomically.
 * Some attempted update operations on this map by other threads
 * may be blocked while computation is in progress, so the
 * computation should be short and simple, and must not attempt to
 * update any other mappings of this Map.
+ * The supplied function is invoked exactly once per invocation of
+ * this method. Some attempted update operations on this map by
+ * other threads may be blocked while computation is in progress,
+ * so the computation should be short and simple.
+ *
+ * <p>The remapping function must not modify this map during computation.
*
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or remappingFunction
* is null
* @throws IllegalStateException if the computation detectably
* attempts a recursive update to this map that would
* otherwise never complete
* @throws RuntimeException or Error if the remappingFunction does so,
* in which case the mapping is unchanged
*/
public V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
 csr of

JDK8231592 Clarify that ConcurrentHashMap compute methods mapping functions execute at most once
 Resolved