--- jsr166/src/jsr166e/ConcurrentHashMapV8.java 2011/08/30 07:23:35 1.4 +++ jsr166/src/jsr166e/ConcurrentHashMapV8.java 2011/08/30 14:55:58 1.9 @@ -54,7 +54,7 @@ import java.io.Serializable; *

Resizing this or any other kind of hash table is a relatively * slow operation, so, when possible, it is a good idea to provide * estimates of expected table sizes in constructors. Also, for - * compatability with previous versions of this class, constructors + * compatibility with previous versions of this class, constructors * may optionally specify an expected {@code concurrencyLevel} as an * additional hint for internal sizing. * @@ -83,8 +83,8 @@ public class ConcurrentHashMapV8 /** * A function computing a mapping from the given key to a value, - * or null if there is no mapping. This is a - * place-holder for an upcoming JDK8 interface. + * or {@code null} if there is no mapping. This is a place-holder + * for an upcoming JDK8 interface. */ public static interface MappingFunction { /** @@ -146,11 +146,15 @@ public class ConcurrentHashMapV8 * there is no existing node during a put operation, then one can * be CAS'ed in (without need for lock except in computeIfAbsent); * the CAS serves as validation. This is on average the most - * common case for put operations. The expected number of locks - * covering different elements (i.e., bins with 2 or more nodes) - * is approximately 10% at steady state under default settings. - * Lock contention probability for two threads accessing arbitrary - * distinct elements is thus less than 1% even for small tables. + * common case for put operations -- under random hash codes, the + * distribution of nodes in bins follows a Poisson distribution + * (see http://en.wikipedia.org/wiki/Poisson_distribution) with a + * parameter of 0.5 on average under the default loadFactor of + * 0.75. The expected number of locks covering different elements + * (i.e., bins with 2 or more nodes) is approximately 10% at + * steady state under default settings. Lock contention + * probability for two threads accessing arbitrary distinct + * elements is, roughly, 1 / (8 * #elements). * * The table is resized when occupancy exceeds a threshold. Only * a single thread performs the resize (using field "resizing", to @@ -188,12 +192,12 @@ public class ConcurrentHashMapV8 * in 8 puts check threshold (and after resizing, many fewer do * so). But this approximation has high variance for small table * sizes, so we check on any collision for sizes <= 64. Further, - * to increase the probablity that a resize occurs soon enough, we + * to increase the probability that a resize occurs soon enough, we * offset the threshold (see THRESHOLD_OFFSET) by the expected * number of puts between checks. This is currently set to 8, in * accord with the default load factor. In practice, this is * rarely overridden, and in any case is close enough to other - * plausible values not to waste dynamic probablity computation + * plausible values not to waste dynamic probability computation * for more precision. */ @@ -213,7 +217,7 @@ public class ConcurrentHashMapV8 /** * The default initial table capacity. Must be a power of 2, at - * least MINIMUM_CAPACITY and at most MAXIMUM_CAPACITY + * least MINIMUM_CAPACITY and at most MAXIMUM_CAPACITY. */ static final int DEFAULT_CAPACITY = 16; @@ -230,7 +234,7 @@ public class ConcurrentHashMapV8 static final int DEFAULT_CONCURRENCY_LEVEL = 16; /** - * The count value to offset thesholds to compensate for checking + * The count value to offset thresholds to compensate for checking * for resizing only when inserting into bins with two or more * elements. See above for explanation. */ @@ -267,7 +271,7 @@ public class ConcurrentHashMapV8 transient Set> entrySet; transient Collection values; - /** For serialization compatability. Null unless serialized; see below */ + /** For serialization compatibility. Null unless serialized; see below */ Segment[] segments; /** @@ -305,7 +309,7 @@ public class ConcurrentHashMapV8 } /* - * Volatile access nethods are used for table elements as well as + * Volatile access methods are used for table elements as well as * elements of in-progress next table while resizing. Uses in * access and update methods are null checked by callers, and * implicitly bounds-checked, relying on the invariants that tab @@ -515,6 +519,8 @@ public class ConcurrentHashMapV8 } else if (e.hash < 0) tab = (Node[])e.key; + else if (Thread.holdsLock(e)) + throw new IllegalStateException("Recursive map computation"); else { boolean checkSize = false; synchronized (e) { @@ -903,7 +909,7 @@ public class ConcurrentHashMapV8 * nonpositive. */ public ConcurrentHashMapV8(int initialCapacity, - float loadFactor, int concurrencyLevel) { + float loadFactor, int concurrencyLevel) { if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) throw new IllegalArgumentException(); this.initCap = initialCapacity; @@ -983,9 +989,7 @@ public class ConcurrentHashMapV8 */ public int size() { long n = counter.sum(); - return (n <= 0L) ? 0 : - (n >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : - (int)n; + return ((n >>> 31) == 0) ? (int)n : (n < 0L) ? 0 : Integer.MAX_VALUE; } /** @@ -1119,11 +1123,16 @@ public class ConcurrentHashMapV8 * * * except that the action is performed atomically. Some attempted - * 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 common usage is to construct a new object - * serving as an initial mapped value, or memoized result. + * 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() {
+     *   public V map(K k) { return new Value(f(k)); }};
+     * }
* * @param key key with which the specified value is to be associated * @param mappingFunction the function to compute a value @@ -1132,6 +1141,9 @@ public class ConcurrentHashMapV8 * returned {@code 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. */ @@ -1142,7 +1154,7 @@ public class ConcurrentHashMapV8 } /** - * Computes the value associated with he given key using the given + * Computes the value associated with the given key using the given * mappingFunction, and if non-null, enters it into the map. This * is equivalent to * @@ -1151,14 +1163,15 @@ public class ConcurrentHashMapV8 * if (value != null) * map.put(key, value); * else - * return map.get(key); + * value = map.get(key); + * return value; * * * except that the action is performed atomically. Some attempted - * 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. + * 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. * * @param key key with which the specified value is to be associated * @param mappingFunction the function to compute a value @@ -1167,6 +1180,9 @@ public class ConcurrentHashMapV8 * returned {@code null} and the value was not otherwise present. * @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 unchanged. */ @@ -1534,8 +1550,7 @@ public class ConcurrentHashMapV8 } /** - * Reconstitutes the instance from a - * stream (i.e., deserializes it). + * Reconstitutes the instance from a stream (that is, deserializes it). * @param s the stream */ @SuppressWarnings("unchecked")