--- jsr166/src/jsr166e/ConcurrentHashMapV8.java 2012/06/09 17:02:07 1.40 +++ jsr166/src/jsr166e/ConcurrentHashMapV8.java 2012/08/13 15:52:33 1.52 @@ -4,10 +4,12 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -// Snapshot Tue Jun 5 14:56:09 2012 Doug Lea (dl at altair) - package jsr166e; import jsr166e.LongAdder; +import jsr166e.ForkJoinPool; +import jsr166e.ForkJoinTask; + +import java.util.Comparator; import java.util.Arrays; import java.util.Map; import java.util.Set; @@ -25,6 +27,8 @@ import java.util.concurrent.ConcurrentMa import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.AbstractQueuedSynchronizer; +import java.util.concurrent.atomic.AtomicReference; + import java.io.Serializable; /** @@ -90,7 +94,9 @@ import java.io.Serializable; * Java Collections Framework. * *
jsr166e note: This class is a candidate replacement for
- * java.util.concurrent.ConcurrentHashMap.
+ * java.util.concurrent.ConcurrentHashMap. During transition, this
+ * class declares and uses nested functional interfaces with different
+ * names but the same forms as those expected for JDK8.
*
* @since 1.5
* @author Doug Lea
@@ -98,38 +104,76 @@ import java.io.Serializable;
* @param This interface exports a subset of expected JDK8
+ * functionality.
+ *
+ * Sample usage: Here is one (of the several) ways to compute
+ * the sum of the values held in a map using the ForkJoin
+ * framework. As illustrated here, Spliterators are well suited to
+ * designs in which a task repeatedly splits off half its work
+ * into forked subtasks until small enough to process directly,
+ * and then joins these subtasks. Variants of this style can also
+ * be used in completion-based designs.
+ *
+ * The concurrency properties of the bulk operations follow
+ * from those of ConcurrentHashMap: Any non-null result returned
+ * from {@code get(key)} and related access methods bears a
+ * happens-before relation with the associated insertion or
+ * update. The result of any bulk operation reflects the
+ * composition of these per-element relations (but is not
+ * necessarily atomic with respect to the map as a whole unless it
+ * is somehow known to be quiescent). Conversely, because keys
+ * and values in the map are never null, null serves as a reliable
+ * atomic indicator of the current lack of any result. To
+ * maintain this property, null serves as an implicit basis for
+ * all non-scalar reduction operations. For the double, long, and
+ * int versions, the basis should be one that, when combined with
+ * any other value, returns that other value (more formally, it
+ * should be the identity element for the reduction). Most common
+ * reductions have these properties; for example, computing a sum
+ * with basis 0 or a minimum with basis MAX_VALUE.
+ *
+ * Search and transformation functions provided as arguments
+ * should similarly return null to indicate the lack of any result
+ * (in which case it is not used). In the case of mapped
+ * reductions, this also enables transformations to serve as
+ * filters, returning null (or, in the case of primitive
+ * specializations, the identity basis) if the element should not
+ * be combined. You can create compound transformations and
+ * filterings by composing them yourself under this "null means
+ * there is nothing there now" rule before using them in search or
+ * reduce operations.
+ *
+ * Methods accepting and/or returning Entry arguments maintain
+ * key-value associations. They may be useful for example when
+ * finding the key for the greatest value. Note that "plain" Entry
+ * arguments can be supplied using {@code new
+ * AbstractMap.SimpleEntry(k,v)}.
+ *
+ * Bulk operations may complete abruptly, throwing an
+ * exception encountered in the application of a supplied
+ * function. Bear in mind when handling such exceptions that other
+ * concurrently executing functions could also have thrown
+ * exceptions, or would have done so if the first exception had
+ * not occurred.
+ *
+ * Parallel speedups compared to sequential processing are
+ * common but not guaranteed. Operations involving brief
+ * functions on small maps may execute more slowly than sequential
+ * loops if the underlying work to parallelize the computation is
+ * more expensive than the computation itself. Similarly,
+ * parallelization may not lead to much actual parallelism if all
+ * processors are busy performing unrelated tasks.
+ *
+ * All arguments to all task methods must be non-null.
+ *
+ * jsr166e note: During transition, this class
+ * uses nested functional interfaces with different names but the
+ * same forms as those expected for JDK8.
+ */
+ public class Parallel {
+ final ForkJoinPool fjp;
+
+ /**
+ * Returns an extended view of this map using the given
+ * executor for bulk parallel operations.
+ *
+ * @param executor the executor
+ */
+ public Parallel(ForkJoinPool executor) {
+ this.fjp = executor;
+ }
+ /**
+ * Performs the given action for each (key, value).
+ *
+ * @param action the action
+ */
+ public void forEach(BiAction
+ * {@code ConcurrentHashMapV8
*/
- public static interface RemappingFunction {@code
* if (map.containsKey(key))
* return map.get(key);
- * value = mappingFunction.map(key);
- * map.put(key, value);
+ * value = mappingFunction.apply(key);
+ * if (value != null)
+ * map.put(key, value);
* return value;}
*
* except that the action is performed atomically. If the
- * function returns {@code null} (in which case a {@code
- * NullPointerException} is thrown), or the function itself throws
- * an (unchecked) exception, the exception is rethrown to its
- * caller, and no mapping is recorded. 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 most appropriate usage is to construct a new
- * object serving as an initial mapped value, or memoized result,
- * as in:
+ * function returns {@code null} no mapping is recorded. If the
+ * function itself throws an (unchecked) exception, the exception
+ * is rethrown to its caller, and no mapping is recorded. 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 most appropriate usage is to
+ * construct a new object serving as an initial mapped value, or
+ * memoized result, as in:
*
* {@code
- * map.computeIfAbsent(key, new MappingFunction
*
* @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.
- * @throws NullPointerException if the specified key, mappingFunction,
- * or computed value is null
+ * 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
@@ -2437,55 +2626,131 @@ public class ConcurrentHashMapV8 {@code
+ * if (map.containsKey(key)) {
+ * value = remappingFunction.apply(key, map.get(key));
+ * if (value != null)
+ * map.put(key, value);
+ * else
+ * map.remove(key);
+ * }
+ * }
+ *
+ * except that the action is performed atomically. If the
+ * function returns {@code null}, the mapping is removed. If the
+ * function itself throws an (unchecked) exception, the exception
+ * is rethrown to its caller, and the current mapping is left
+ * unchanged. 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. For example,
+ * to either create or append new messages to a value mapping:
+ *
+ * @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 computeIfPresent(K key, BiFun super K, ? super V, ? extends V> remappingFunction) {
+ if (key == null || remappingFunction == null)
+ throw new NullPointerException();
+ return (V)internalCompute(key, true, remappingFunction);
+ }
+
+ /**
+ * Computes a new mapping value given a key and
* its current mapped value (or {@code null} if there is no current
* mapping). This is equivalent to
* {@code
- * map.put(key, remappingFunction.remap(key, map.get(key));
+ * value = remappingFunction.apply(key, map.get(key));
+ * if (value != null)
+ * map.put(key, value);
+ * else
+ * map.remove(key);
* }
*
* except that the action is performed atomically. If the
- * function returns {@code null} (in which case a {@code
- * NullPointerException} is thrown), or the function itself throws
- * an (unchecked) exception, the exception is rethrown to its
- * caller, and current mapping is left unchanged. 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. For example, to either create or
- * append new messages to a value mapping:
+ * function returns {@code null}, the mapping is removed. If the
+ * function itself throws an (unchecked) exception, the exception
+ * is rethrown to its caller, and the current mapping is left
+ * unchanged. 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. For example,
+ * to either create or append new messages to a value mapping:
*
* {@code
* Map
*
* @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.
+ * the specified key, or null if none.
* @throws NullPointerException if the specified key or remappingFunction
- * or computed value is null
+ * 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
*/
- @SuppressWarnings("unchecked")
- public V compute(K key, RemappingFunction super K, V> remappingFunction) {
+ // @SuppressWarnings("unchecked")
+ public V compute(K key, BiFun super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
- return (V)internalCompute(key, remappingFunction);
+ return (V)internalCompute(key, false, remappingFunction);
+ }
+
+ /**
+ * If the specified key is not already associated
+ * with a value, associate it with the given value.
+ * Otherwise, replace the value with the results of
+ * the given remapping function. This is equivalent to:
+ * {@code
+ * if (!map.containsKey(key))
+ * map.put(value);
+ * else {
+ * newValue = remappingFunction.apply(map.get(key), value);
+ * if (value != null)
+ * map.put(key, value);
+ * else
+ * map.remove(key);
+ * }
+ * }
+ * except that the action is performed atomically. If the
+ * function returns {@code null}, the mapping is removed. If the
+ * function itself throws an (unchecked) exception, the exception
+ * is rethrown to its caller, and the current mapping is left
+ * unchanged. 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.
+ */
+ // @SuppressWarnings("unchecked")
+ public V merge(K key, V value, BiFun super V, ? super V, ? extends V> remappingFunction) {
+ if (key == null || value == null || remappingFunction == null)
+ throw new NullPointerException();
+ return (V)internalMerge(key, value, remappingFunction);
}
/**
@@ -2498,7 +2763,7 @@ public class ConcurrentHashMapV8
+ *
+ *
+ *
+ *
+ *
+ *