ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/ConcurrentHashMapV8.java
(Generate patch)

Comparing jsr166/src/jsr166e/ConcurrentHashMapV8.java (file contents):
Revision 1.8 by jsr166, Tue Aug 30 13:49:10 2011 UTC vs.
Revision 1.22 by jsr166, Sat Sep 10 19:33:14 2011 UTC

# Line 49 | Line 49 | import java.io.Serializable;
49   * are typically useful only when a map is not undergoing concurrent
50   * updates in other threads.  Otherwise the results of these methods
51   * reflect transient states that may be adequate for monitoring
52 < * purposes, but not for program control.
52 > * or estimation purposes, but not for program control.
53   *
54 < * <p> Resizing this or any other kind of hash table is a relatively
55 < * slow operation, so, when possible, it is a good idea to provide
56 < * estimates of expected table sizes in constructors. Also, for
57 < * compatibility with previous versions of this class, constructors
58 < * may optionally specify an expected {@code concurrencyLevel} as an
59 < * additional hint for internal sizing.
54 > * <p> The table is dynamically expanded when there are too many
55 > * collisions (i.e., keys that have distinct hash codes but fall into
56 > * the same slot modulo the table size), with the expected average
57 > * effect of maintaining roughly two bins per mapping. There may be
58 > * much variance around this average as mappings are added and
59 > * removed, but overall, this maintains a commonly accepted time/space
60 > * tradeoff for hash tables.  However, resizing this or any other kind
61 > * of hash table may be a relatively slow operation. When possible, it
62 > * is a good idea to provide a size estimate as an optional {@code
63 > * initialCapacity} constructor argument. An additional optional
64 > * {@code loadFactor} constructor argument provides a further means of
65 > * customizing initial table capacity by specifying the table density
66 > * to be used in calculating the amount of space to allocate for the
67 > * given number of elements.  Also, for compatibility with previous
68 > * versions of this class, constructors may optionally specify an
69 > * expected {@code concurrencyLevel} as an additional hint for
70 > * internal sizing.  Note that using many keys with exactly the same
71 > * {@code hashCode{}} is a sure way to slow down performance of any
72 > * hash table.
73   *
74   * <p>This class and its views and iterators implement all of the
75   * <em>optional</em> methods of the {@link Map} and {@link Iterator}
# Line 113 | Line 126 | public class ConcurrentHashMapV8<K, V>
126       * Each key-value mapping is held in a Node.  Because Node fields
127       * can contain special values, they are defined using plain Object
128       * types. Similarly in turn, all internal methods that use them
129 <     * work off Object types. All public generic-typed methods relay
130 <     * in/out of these internal methods, supplying casts as needed.
129 >     * work off Object types. And similarly, so do the internal
130 >     * methods of auxiliary iterator and view classes.  All public
131 >     * generic typed methods relay in/out of these internal methods,
132 >     * supplying null-checks and casts as needed.
133       *
134       * The table is lazily initialized to a power-of-two size upon the
135 <     * first insertion.  Each bin in the table contains a (typically
136 <     * short) list of Nodes.  Table accesses require volatile/atomic
137 <     * reads, writes, and CASes.  Because there is no other way to
138 <     * arrange this without adding further indirections, we use
139 <     * intrinsics (sun.misc.Unsafe) operations.  The lists of nodes
140 <     * within bins are always accurately traversable under volatile
141 <     * reads, so long as lookups check hash code and non-nullness of
142 <     * key and value before checking key equality. (All valid hash
143 <     * codes are nonnegative. Negative values are reserved for special
144 <     * forwarding nodes; see below.)
145 <     *
146 <     * A bin may be locked during update (insert, delete, and replace)
147 <     * operations.  We do not want to waste the space required to
148 <     * associate a distinct lock object with each bin, so instead use
149 <     * the first node of a bin list itself as a lock, using builtin
150 <     * "synchronized" locks. These save space and we can live with
151 <     * only plain block-structured lock/unlock operations. Using the
152 <     * first node of a list as a lock does not by itself suffice
153 <     * though: When a node is locked, any update must first validate
154 <     * that it is still the first node, and retry if not. (Because new
155 <     * nodes are always appended to lists, once a node is first in a
156 <     * bin, it remains first until deleted or the bin becomes
157 <     * invalidated.)  However, update operations can and usually do
158 <     * still traverse the bin until the point of update, which helps
159 <     * reduce cache misses on retries.  This is a converse of sorts to
160 <     * the lazy locking technique described by Herlihy & Shavit. If
161 <     * there is no existing node during a put operation, then one can
162 <     * be CAS'ed in (without need for lock except in computeIfAbsent);
163 <     * the CAS serves as validation. This is on average the most
164 <     * common case for put operations -- under random hash codes, the
165 <     * distribution of nodes in bins follows a Poisson distribution
166 <     * (see http://en.wikipedia.org/wiki/Poisson_distribution) with a
167 <     * parameter of 0.5 on average under the default loadFactor of
168 <     * 0.75.  The expected number of locks covering different elements
169 <     * (i.e., bins with 2 or more nodes) is approximately 10% at
170 <     * steady state under default settings.  Lock contention
171 <     * probability for two threads accessing arbitrary distinct
172 <     * elements is, roughly, 1 / (8 * #elements).
135 >     * first insertion.  Each bin in the table contains a list of
136 >     * Nodes (most often, zero or one Node).  Table accesses require
137 >     * volatile/atomic reads, writes, and CASes.  Because there is no
138 >     * other way to arrange this without adding further indirections,
139 >     * we use intrinsics (sun.misc.Unsafe) operations.  The lists of
140 >     * nodes within bins are always accurately traversable under
141 >     * volatile reads, so long as lookups check hash code and
142 >     * non-nullness of value before checking key equality. (All valid
143 >     * hash codes are nonnegative. Negative values are reserved for
144 >     * special forwarding nodes; see below.)
145 >     *
146 >     * Insertion (via put or putIfAbsent) of the first node in an
147 >     * empty bin is performed by just CASing it to the bin.  This is
148 >     * on average by far the most common case for put operations.
149 >     * Other update operations (insert, delete, and replace) require
150 >     * locks.  We do not want to waste the space required to associate
151 >     * a distinct lock object with each bin, so instead use the first
152 >     * node of a bin list itself as a lock, using plain "synchronized"
153 >     * locks. These save space and we can live with block-structured
154 >     * lock/unlock operations. Using the first node of a list as a
155 >     * lock does not by itself suffice though: When a node is locked,
156 >     * any update must first validate that it is still the first node,
157 >     * and retry if not. Because new nodes are always appended to
158 >     * lists, once a node is first in a bin, it remains first until
159 >     * deleted or the bin becomes invalidated.  However, operations
160 >     * that only conditionally update can and sometimes do inspect
161 >     * nodes until the point of update. This is a converse of sorts to
162 >     * the lazy locking technique described by Herlihy & Shavit.
163 >     *
164 >     * The main disadvantage of this approach is that most update
165 >     * operations on other nodes in a bin list protected by the same
166 >     * lock can stall, for example when user equals() or mapping
167 >     * functions take a long time.  However, statistically, this is
168 >     * not a common enough problem to outweigh the time/space overhead
169 >     * of alternatives: Under random hash codes, the frequency of
170 >     * nodes in bins follows a Poisson distribution
171 >     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
172 >     * parameter of about 0.5 on average, given the resizing threshold
173 >     * of 0.75, although with a large variance because of resizing
174 >     * granularity. Ignoring variance, the expected occurrences of
175 >     * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The
176 >     * first few values are:
177 >     *
178 >     * 0:    0.607
179 >     * 1:    0.303
180 >     * 2:    0.076
181 >     * 3:    0.012
182 >     * more: 0.002
183 >     *
184 >     * Lock contention probability for two threads accessing distinct
185 >     * elements is roughly 1 / (8 * #elements).  Function "spread"
186 >     * performs hashCode randomization that improves the likelihood
187 >     * that these assumptions hold unless users define exactly the
188 >     * same value for too many hashCodes.
189       *
190       * The table is resized when occupancy exceeds a threshold.  Only
191       * a single thread performs the resize (using field "resizing", to
192       * arrange exclusion), but the table otherwise remains usable for
193 <     * both reads and updates. Resizing proceeds by transferring bins,
194 <     * one by one, from the table to the next table.  Upon transfer,
195 <     * the old table bin contains only a special forwarding node (with
196 <     * negative hash code ("MOVED")) that contains the next table as
197 <     * its key. On encountering a forwarding node, access and update
193 >     * reads and updates. Resizing proceeds by transferring bins, one
194 >     * by one, from the table to the next table.  Upon transfer, the
195 >     * old table bin contains only a special forwarding node (with
196 >     * negative hash field) that contains the next table as its
197 >     * key. On encountering a forwarding node, access and update
198       * operations restart, using the new table. To ensure concurrent
199       * readability of traversals, transfers must proceed from the last
200 <     * bin (table.length - 1) up towards the first.  Any traversal
201 <     * starting from the first bin can then arrange to move to the new
202 <     * table for the rest of the traversal without revisiting nodes.
203 <     * This constrains bin transfers to a particular order, and so can
204 <     * block indefinitely waiting for the next lock, and other threads
205 <     * cannot help with the transfer. However, expected stalls are
206 <     * infrequent enough to not warrant the additional overhead and
207 <     * complexity of access and iteration schemes that could admit
208 <     * out-of-order or concurrent bin transfers.
209 <     *
210 <     * A similar traversal scheme (not yet implemented) can apply to
211 <     * partial traversals during partitioned aggregate operations.
212 <     * Also, read-only operations give up if ever forwarded to a null
213 <     * table, which provides support for shutdown-style clearing,
214 <     * which is also not currently implemented.
200 >     * bin (table.length - 1) up towards the first.  Upon seeing a
201 >     * forwarding node, traversals (see class InternalIterator)
202 >     * arrange to move to the new table for the rest of the traversal
203 >     * without revisiting nodes.  This constrains bin transfers to a
204 >     * particular order, and so can block indefinitely waiting for the
205 >     * next lock, and other threads cannot help with the transfer.
206 >     * However, expected stalls are infrequent enough to not warrant
207 >     * the additional overhead of access and iteration schemes that
208 >     * could admit out-of-order or concurrent bin transfers.
209 >     *
210 >     * This traversal scheme also applies to partial traversals of
211 >     * ranges of bins (via an alternate InternalIterator constructor)
212 >     * to support partitioned aggregate operations (that are not
213 >     * otherwise implemented yet).  Also, read-only operations give up
214 >     * if ever forwarded to a null table, which provides support for
215 >     * shutdown-style clearing, which is also not currently
216 >     * implemented.
217 >     *
218 >     * Lazy table initialization minimizes footprint until first use,
219 >     * and also avoids resizings when the first operation is from a
220 >     * putAll, constructor with map argument, or deserialization.
221 >     * These cases attempt to override the targetCapacity used in
222 >     * growTable. These harmlessly fail to take effect in cases of
223 >     * races with other ongoing resizings. Uses of the threshold and
224 >     * targetCapacity during attempted initializations or resizings
225 >     * are racy but fall back on checks to preserve correctness.
226       *
227       * The element count is maintained using a LongAdder, which avoids
228       * contention on updates but can encounter cache thrashing if read
229 <     * too frequently during concurrent updates. To avoid reading so
229 >     * too frequently during concurrent access. To avoid reading so
230       * often, resizing is normally attempted only upon adding to a bin
231 <     * already holding two or more nodes. Under the default threshold
232 <     * (0.75), and uniform hash distributions, the probability of this
233 <     * occurring at threshold is around 13%, meaning that only about 1
234 <     * in 8 puts check threshold (and after resizing, many fewer do
235 <     * so). But this approximation has high variance for small table
236 <     * sizes, so we check on any collision for sizes <= 64.  Further,
237 <     * to increase the probability that a resize occurs soon enough, we
238 <     * offset the threshold (see THRESHOLD_OFFSET) by the expected
239 <     * number of puts between checks. This is currently set to 8, in
240 <     * accord with the default load factor. In practice, this is
241 <     * rarely overridden, and in any case is close enough to other
242 <     * plausible values not to waste dynamic probability computation
243 <     * for more precision.
231 >     * already holding two or more nodes. Under uniform hash
232 >     * distributions, the probability of this occurring at threshold
233 >     * is around 13%, meaning that only about 1 in 8 puts check
234 >     * threshold (and after resizing, many fewer do so). But this
235 >     * approximation has high variance for small table sizes, so we
236 >     * check on any collision for sizes <= 64.  Further, to increase
237 >     * the probability that a resize occurs soon enough, we offset the
238 >     * threshold (see THRESHOLD_OFFSET) by the expected number of puts
239 >     * between checks.
240 >     *
241 >     * Maintaining API and serialization compatibility with previous
242 >     * versions of this class introduces several oddities. Mainly: We
243 >     * leave untouched but unused constructor arguments refering to
244 >     * concurrencyLevel. We also declare an unused "Segment" class
245 >     * that is instantiated in minimal form only when serializing.
246       */
247  
248      /* ---------------- Constants -------------- */
249  
250      /**
251 <     * The smallest allowed table capacity.  Must be a power of 2, at
252 <     * least 2.
251 >     * The largest possible table capacity.  This value must be
252 >     * exactly 1<<30 to stay within Java array allocation and indexing
253 >     * bounds for power of two table sizes.
254       */
255 <    static final int MINIMUM_CAPACITY = 2;
255 >    private static final int MAXIMUM_CAPACITY = 1 << 30;
256  
257      /**
258 <     * The largest allowed table capacity.  Must be a power of 2, at
259 <     * most 1<<30.
258 >     * The default initial table capacity.  Must be a power of 2
259 >     * (i.e., at least 1) and at most MAXIMUM_CAPACITY.
260       */
261 <    static final int MAXIMUM_CAPACITY = 1 << 30;
261 >    private static final int DEFAULT_CAPACITY = 16;
262  
263      /**
264 <     * The default initial table capacity.  Must be a power of 2, at
265 <     * least MINIMUM_CAPACITY and at most MAXIMUM_CAPACITY
264 >     * The load factor for this table. Overrides of this value in
265 >     * constructors affect only the initial table capacity.  The
266 >     * actual floating point value isn't normally used, because it is
267 >     * simpler to rely on the expression {@code n - (n >>> 2)} for the
268 >     * associated resizing threshold.
269       */
270 <    static final int DEFAULT_CAPACITY = 16;
270 >    private static final float LOAD_FACTOR = 0.75f;
271  
272      /**
273 <     * The default load factor for this table, used when not otherwise
274 <     * specified in a constructor.
273 >     * The count value to offset thresholds to compensate for checking
274 >     * for the need to resize only when inserting into bins with two
275 >     * or more elements. See above for explanation.
276       */
277 <    static final float DEFAULT_LOAD_FACTOR = 0.75f;
277 >    private static final int THRESHOLD_OFFSET = 8;
278  
279      /**
280 <     * The default concurrency level for this table. Unused, but
281 <     * defined for compatibility with previous versions of this class.
280 >     * The default concurrency level for this table. Unused except as
281 >     * a sizing hint, but defined for compatibility with previous
282 >     * versions of this class.
283       */
284 <    static final int DEFAULT_CONCURRENCY_LEVEL = 16;
284 >    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
285 >
286 >    /* ---------------- Nodes -------------- */
287  
288      /**
289 <     * The count value to offset thresholds to compensate for checking
290 <     * for resizing only when inserting into bins with two or more
291 <     * elements. See above for explanation.
289 >     * Key-value entry. Note that this is never exported out as a
290 >     * user-visible Map.Entry. Nodes with a negative hash field are
291 >     * special, and do not contain user keys or values.  Otherwise,
292 >     * keys are never null, and null val fields indicate that a node
293 >     * is in the process of being deleted or created. For purposes of
294 >     * read-only, access, a key may be read before a val, but can only
295 >     * be used after checking val.  (For an update operation, when a
296 >     * lock is held on a node, order doesn't matter.)
297       */
298 <    static final int THRESHOLD_OFFSET = 8;
298 >    static final class Node {
299 >        final int hash;
300 >        final Object key;
301 >        volatile Object val;
302 >        volatile Node next;
303 >
304 >        Node(int hash, Object key, Object val, Node next) {
305 >            this.hash = hash;
306 >            this.key = key;
307 >            this.val = val;
308 >            this.next = next;
309 >        }
310 >    }
311  
312      /**
313 <     * Special node hash value indicating to use table in node.key
245 <     * Must be negative.
313 >     * Sign bit of node hash value indicating to use table in node.key.
314       */
315 <    static final int MOVED = -1;
315 >    private static final int SIGN_BIT = 0x80000000;
316  
317      /* ---------------- Fields -------------- */
318  
319      /**
320       * The array of bins. Lazily initialized upon first insertion.
321 <     * Size is always a power of two. Accessed directly by inner
254 <     * classes.
321 >     * Size is always a power of two. Accessed directly by iterators.
322       */
323      transient volatile Node[] table;
324  
# Line 259 | Line 326 | public class ConcurrentHashMapV8<K, V>
326      private transient final LongAdder counter;
327      /** Nonzero when table is being initialized or resized. Updated via CAS. */
328      private transient volatile int resizing;
262    /** The target load factor for the table. */
263    private transient float loadFactor;
329      /** The next element count value upon which to resize the table. */
330      private transient int threshold;
331 <    /** The initial capacity of the table. */
332 <    private transient int initCap;
331 >    /** The target capacity; volatile to cover initialization races. */
332 >    private transient volatile int targetCapacity;
333  
334      // views
335 <    transient Set<K> keySet;
336 <    transient Set<Map.Entry<K,V>> entrySet;
337 <    transient Collection<V> values;
335 >    private transient KeySet<K,V> keySet;
336 >    private transient Values<K,V> values;
337 >    private transient EntrySet<K,V> entrySet;
338  
339      /** For serialization compatibility. Null unless serialized; see below */
340 <    Segment<K,V>[] segments;
340 >    private Segment<K,V>[] segments;
341  
342 <    /**
278 <     * Applies a supplemental hash function to a given hashCode, which
279 <     * defends against poor quality hash functions.  The result must
280 <     * be non-negative, and for reasonable performance must have good
281 <     * avalanche properties; i.e., that each bit of the argument
282 <     * affects each bit (except sign bit) of the result.
283 <     */
284 <    private static final int spread(int h) {
285 <        // Apply base step of MurmurHash; see http://code.google.com/p/smhasher/
286 <        h ^= h >>> 16;
287 <        h *= 0x85ebca6b;
288 <        h ^= h >>> 13;
289 <        h *= 0xc2b2ae35;
290 <        return (h >>> 16) ^ (h & 0x7fffffff); // mask out sign bit
291 <    }
292 <
293 <    /**
294 <     * Key-value entry. Note that this is never exported out as a
295 <     * user-visible Map.Entry.
296 <     */
297 <    static final class Node {
298 <        final int hash;
299 <        final Object key;
300 <        volatile Object val;
301 <        volatile Node next;
302 <
303 <        Node(int hash, Object key, Object val, Node next) {
304 <            this.hash = hash;
305 <            this.key = key;
306 <            this.val = val;
307 <            this.next = next;
308 <        }
309 <    }
342 >    /* ---------------- Table element access -------------- */
343  
344      /*
345       * Volatile access methods are used for table elements as well as
346 <     * elements of in-progress next table while resizing.  Uses in
347 <     * access and update methods are null checked by callers, and
348 <     * implicitly bounds-checked, relying on the invariants that tab
349 <     * arrays have non-zero size, and all indices are masked with
350 <     * (tab.length - 1) which is never negative and always less than
351 <     * length. The "relaxed" non-volatile forms are used only during
352 <     * table initialization. The only other usage is in
353 <     * HashIterator.advance, which performs explicit checks.
346 >     * elements of in-progress next table while resizing.  Uses are
347 >     * null checked by callers, and implicitly bounds-checked, relying
348 >     * on the invariants that tab arrays have non-zero size, and all
349 >     * indices are masked with (tab.length - 1) which is never
350 >     * negative and always less than length. Note that, to be correct
351 >     * wrt arbitrary concurrency errors by users, bounds checks must
352 >     * operate on local variables, which accounts for some odd-looking
353 >     * inline assignments below.
354       */
355  
356 <    static final Node tabAt(Node[] tab, int i) { // used in HashIterator
356 >    static final Node tabAt(Node[] tab, int i) { // used by InternalIterator
357          return (Node)UNSAFE.getObjectVolatile(tab, ((long)i<<ASHIFT)+ABASE);
358      }
359  
# Line 332 | Line 365 | public class ConcurrentHashMapV8<K, V>
365          UNSAFE.putObjectVolatile(tab, ((long)i<<ASHIFT)+ABASE, v);
366      }
367  
368 <    private static final Node relaxedTabAt(Node[] tab, int i) {
369 <        return (Node)UNSAFE.getObject(tab, ((long)i<<ASHIFT)+ABASE);
368 >    /* ----------------Table Initialization and Resizing -------------- */
369 >
370 >    /**
371 >     * Returns a power of two table size for the given desired capacity.
372 >     * See Hackers Delight, sec 3.2
373 >     */
374 >    private static final int tableSizeFor(int c) {
375 >        int n = c - 1;
376 >        n |= n >>> 1;
377 >        n |= n >>> 2;
378 >        n |= n >>> 4;
379 >        n |= n >>> 8;
380 >        n |= n >>> 16;
381 >        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
382      }
383  
384 <    private static final void relaxedSetTabAt(Node[] tab, int i, Node v) {
385 <        UNSAFE.putObject(tab, ((long)i<<ASHIFT)+ABASE, v);
384 >    /**
385 >     * If not already resizing, initializes or creates next table and
386 >     * transfers bins. Initial table size uses the capacity recorded
387 >     * in targetCapacity.  Rechecks occupancy after a transfer to see
388 >     * if another resize is already needed because resizings are
389 >     * lagging additions.
390 >     *
391 >     * @return current table
392 >     */
393 >    private final Node[] growTable() {
394 >        if (resizing == 0 &&
395 >            UNSAFE.compareAndSwapInt(this, resizingOffset, 0, 1)) {
396 >            try {
397 >                for (;;) {
398 >                    Node[] tab = table;
399 >                    int n, c, m;
400 >                    if (tab == null)
401 >                        n = (c = targetCapacity) > 0 ? c : DEFAULT_CAPACITY;
402 >                    else if ((m = tab.length) < MAXIMUM_CAPACITY &&
403 >                             counter.sum() >= (long)threshold)
404 >                        n = m << 1;
405 >                    else
406 >                        break;
407 >                    threshold = n - (n >>> 2) - THRESHOLD_OFFSET;
408 >                    Node[] nextTab = new Node[n];
409 >                    if (tab != null)
410 >                        transfer(tab, nextTab,
411 >                                 new Node(SIGN_BIT, nextTab, null, null));
412 >                    table = nextTab;
413 >                    if (tab == null)
414 >                        break;
415 >                }
416 >            } finally {
417 >                resizing = 0;
418 >            }
419 >        }
420 >        else if (table == null)
421 >            Thread.yield(); // lost initialization race; just spin
422 >        return table;
423 >    }
424 >
425 >    /**
426 >     * Reclassifies nodes in each bin to new table.  Because we are
427 >     * using power-of-two expansion, the elements from each bin must
428 >     * either stay at same index, or move with a power of two
429 >     * offset. We eliminate unnecessary node creation by catching
430 >     * cases where old nodes can be reused because their next fields
431 >     * won't change.  Statistically, only about one-sixth of them need
432 >     * cloning when a table doubles. The nodes they replace will be
433 >     * garbage collectable as soon as they are no longer referenced by
434 >     * any reader thread that may be in the midst of concurrently
435 >     * traversing table.
436 >     *
437 >     * Transfers are done from the bottom up to preserve iterator
438 >     * traversability. On each step, the old bin is locked,
439 >     * moved/copied, and then replaced with a forwarding node.
440 >     */
441 >    private static final void transfer(Node[] tab, Node[] nextTab, Node fwd) {
442 >        int n = tab.length;
443 >        Node ignore = nextTab[n + n - 1]; // force bounds check
444 >        for (int i = n - 1; i >= 0; --i) {
445 >            for (Node e;;) {
446 >                if ((e = tabAt(tab, i)) != null) {
447 >                    boolean validated = false;
448 >                    synchronized (e) {
449 >                        if (tabAt(tab, i) == e) {
450 >                            validated = true;
451 >                            Node lo = null, hi = null, lastRun = e;
452 >                            int runBit = e.hash & n;
453 >                            for (Node p = e.next; p != null; p = p.next) {
454 >                                int b = p.hash & n;
455 >                                if (b != runBit) {
456 >                                    runBit = b;
457 >                                    lastRun = p;
458 >                                }
459 >                            }
460 >                            if (runBit == 0)
461 >                                lo = lastRun;
462 >                            else
463 >                                hi = lastRun;
464 >                            for (Node p = e; p != lastRun; p = p.next) {
465 >                                int ph = p.hash;
466 >                                Object pk = p.key, pv = p.val;
467 >                                if ((ph & n) == 0)
468 >                                    lo = new Node(ph, pk, pv, lo);
469 >                                else
470 >                                    hi = new Node(ph, pk, pv, hi);
471 >                            }
472 >                            setTabAt(nextTab, i, lo);
473 >                            setTabAt(nextTab, i + n, hi);
474 >                            setTabAt(tab, i, fwd);
475 >                        }
476 >                    }
477 >                    if (validated)
478 >                        break;
479 >                }
480 >                else if (casTabAt(tab, i, e, fwd))
481 >                    break;
482 >            }
483 >        }
484      }
485  
486 <    /* ---------------- Access and update operations -------------- */
486 >    /* ---------------- Internal access and update methods -------------- */
487  
488 <    /** Implementation for get and containsKey **/
488 >    /**
489 >     * Applies a supplemental hash function to a given hashCode, which
490 >     * defends against poor quality hash functions.  The result must
491 >     * be non-negative, and for reasonable performance must have good
492 >     * avalanche properties; i.e., that each bit of the argument
493 >     * affects each bit (except sign bit) of the result.
494 >     */
495 >    private static final int spread(int h) {
496 >        // Apply base step of MurmurHash; see http://code.google.com/p/smhasher/
497 >        h ^= h >>> 16;
498 >        h *= 0x85ebca6b;
499 >        h ^= h >>> 13;
500 >        h *= 0xc2b2ae35;
501 >        return (h >>> 16) ^ (h & 0x7fffffff); // mask out sign bit
502 >    }
503 >
504 >    /** Implementation for get and containsKey */
505      private final Object internalGet(Object k) {
506          int h = spread(k.hashCode());
507 <        Node[] tab = table;
508 <        retry: while (tab != null) {
509 <            Node e = tabAt(tab, (tab.length - 1) & h);
510 <            while (e != null) {
511 <                int eh = e.hash;
512 <                if (eh == h) {
354 <                    Object ek = e.key, ev = e.val;
355 <                    if (ev != null && ek != null && (k == ek || k.equals(ek)))
507 >        retry: for (Node[] tab = table; tab != null;) {
508 >            Node e; Object ek, ev; int eh;  // locals to read fields once
509 >            for (e = tabAt(tab, (tab.length - 1) & h); e != null; e = e.next) {
510 >                if ((eh = e.hash) == h) {
511 >                    if ((ev = e.val) != null &&
512 >                        ((ek = e.key) == k || k.equals(ek)))
513                          return ev;
514                  }
515 <                else if (eh < 0) { // bin was moved during resize
516 <                    tab = (Node[])e.key;
515 >                else if (eh < 0) {          // sign bit set
516 >                    tab = (Node[])e.key;    // bin was moved during resize
517                      continue retry;
518                  }
362                e = e.next;
519              }
520              break;
521          }
522          return null;
523      }
524  
525 <    /** Implementation for put and putIfAbsent **/
525 >    /** Implementation for put and putIfAbsent */
526      private final Object internalPut(Object k, Object v, boolean replace) {
527          int h = spread(k.hashCode());
528 <        Object oldVal = null;  // the previous value or null if none
529 <        Node[] tab = table;
530 <        for (;;) {
375 <            Node e; int i;
528 >        Object oldVal = null;               // previous value or null if none
529 >        for (Node[] tab = table;;) {
530 >            Node e; int i; Object ek, ev;
531              if (tab == null)
532 <                tab = grow(0);
532 >                tab = growTable();
533              else if ((e = tabAt(tab, i = (tab.length - 1) & h)) == null) {
534                  if (casTabAt(tab, i, null, new Node(h, k, v, null)))
535 <                    break;
535 >                    break;                   // no lock when adding to empty bin
536              }
537 <            else if (e.hash < 0)
537 >            else if (e.hash < 0)             // resized -- restart with new table
538                  tab = (Node[])e.key;
539 +            else if (!replace && e.hash == h && (ev = e.val) != null &&
540 +                     ((ek = e.key) == k || k.equals(ek))) {
541 +                if (tabAt(tab, i) == e) {    // inspect and validate 1st node
542 +                    oldVal = ev;             // without lock for putIfAbsent
543 +                    break;
544 +                }
545 +            }
546              else {
547                  boolean validated = false;
548                  boolean checkSize = false;
549 <                synchronized (e) {
550 <                    Node first = e;
551 <                    for (;;) {
552 <                        Object ek, ev;
553 <                        if ((ev = e.val) == null)
554 <                            break;
555 <                        if (e.hash == h && (ek = e.key) != null &&
394 <                            (k == ek || k.equals(ek))) {
395 <                            if (tabAt(tab, i) == first) {
396 <                                validated = true;
549 >                synchronized (e) {           // lock the 1st node of bin list
550 >                    if (tabAt(tab, i) == e) {
551 >                        validated = true;    // retry if 1st already deleted
552 >                        for (Node first = e;;) {
553 >                            if (e.hash == h &&
554 >                                ((ek = e.key) == k || k.equals(ek)) &&
555 >                                (ev = e.val) != null) {
556                                  oldVal = ev;
557                                  if (replace)
558                                      e.val = v;
559 +                                break;
560                              }
561 <                            break;
562 <                        }
403 <                        Node last = e;
404 <                        if ((e = e.next) == null) {
405 <                            if (tabAt(tab, i) == first) {
406 <                                validated = true;
561 >                            Node last = e;
562 >                            if ((e = e.next) == null) {
563                                  last.next = new Node(h, k, v, null);
564                                  if (last != first || tab.length <= 64)
565                                      checkSize = true;
566 +                                break;
567                              }
411                            break;
568                          }
569                      }
570                  }
571                  if (validated) {
572                      if (checkSize && tab.length < MAXIMUM_CAPACITY &&
573 <                        resizing == 0 && counter.sum() >= threshold)
574 <                        grow(0);
573 >                        resizing == 0 && counter.sum() >= (long)threshold)
574 >                        growTable();
575                      break;
576                  }
577              }
578          }
579          if (oldVal == null)
580 <            counter.increment();
580 >            counter.increment();             // update counter outside of locks
581          return oldVal;
582      }
583  
584      /**
585 <     * Covers the four public remove/replace methods: Replaces node
586 <     * value with v, conditional upon match of cv if non-null.  If
587 <     * resulting value is null, delete.
585 >     * Implementation for the four public remove/replace methods:
586 >     * Replaces node value with v, conditional upon match of cv if
587 >     * non-null.  If resulting value is null, delete.
588       */
589      private final Object internalReplace(Object k, Object v, Object cv) {
590          int h = spread(k.hashCode());
591 <        Object oldVal = null;
592 <        Node e; int i;
593 <        Node[] tab = table;
594 <        while (tab != null &&
595 <               (e = tabAt(tab, i = (tab.length - 1) & h)) != null) {
596 <            if (e.hash < 0)
591 >        for (Node[] tab = table;;) {
592 >            Node e; int i;
593 >            if (tab == null ||
594 >                (e = tabAt(tab, i = (tab.length - 1) & h)) == null)
595 >                return null;
596 >            else if (e.hash < 0)
597                  tab = (Node[])e.key;
598              else {
599 +                Object oldVal = null;
600                  boolean validated = false;
601                  boolean deleted = false;
602                  synchronized (e) {
603 <                    Node pred = null;
604 <                    Node first = e;
605 <                    for (;;) {
606 <                        Object ek, ev;
607 <                        if ((ev = e.val) == null)
608 <                            break;
609 <                        if (e.hash == h && (ek = e.key) != null &&
610 <                            (k == ek || k.equals(ek))) {
454 <                            if (tabAt(tab, i) == first) {
455 <                                validated = true;
603 >                    if (tabAt(tab, i) == e) {
604 >                        validated = true;
605 >                        Node pred = null;
606 >                        do {
607 >                            Object ek, ev;
608 >                            if (e.hash == h &&
609 >                                ((ek = e.key) == k || k.equals(ek)) &&
610 >                                ((ev = e.val) != null)) {
611                                  if (cv == null || cv == ev || cv.equals(ev)) {
612                                      oldVal = ev;
613                                      if ((e.val = v) == null) {
# Line 464 | Line 619 | public class ConcurrentHashMapV8<K, V>
619                                              setTabAt(tab, i, en);
620                                      }
621                                  }
622 +                                break;
623                              }
624 <                            break;
469 <                        }
470 <                        pred = e;
471 <                        if ((e = e.next) == null) {
472 <                            if (tabAt(tab, i) == first)
473 <                                validated = true;
474 <                            break;
475 <                        }
624 >                        } while ((e = (pred = e).next) != null);
625                      }
626                  }
627                  if (validated) {
628                      if (deleted)
629                          counter.decrement();
630 <                    break;
630 >                    return oldVal;
631                  }
632              }
633          }
485        return oldVal;
634      }
635  
636 <    /** Implementation for computeIfAbsent and compute */
636 >    /** Implementation for computeIfAbsent and compute. Like put, but messier. */
637      @SuppressWarnings("unchecked")
638      private final V internalCompute(K k,
639                                      MappingFunction<? super K, ? extends V> f,
# Line 493 | Line 641 | public class ConcurrentHashMapV8<K, V>
641          int h = spread(k.hashCode());
642          V val = null;
643          boolean added = false;
496        boolean validated = false;
644          Node[] tab = table;
645 <        do {
646 <            Node e; int i;
645 >        outer:for (;;) {
646 >            Node e; int i; Object ek, ev;
647              if (tab == null)
648 <                tab = grow(0);
648 >                tab = growTable();
649              else if ((e = tabAt(tab, i = (tab.length - 1) & h)) == null) {
650                  Node node = new Node(h, k, null, null);
651 <                synchronized (node) {
651 >                boolean validated = false;
652 >                synchronized (node) {  // must lock while computing value
653                      if (casTabAt(tab, i, null, node)) {
654                          validated = true;
655                          try {
# Line 516 | Line 664 | public class ConcurrentHashMapV8<K, V>
664                          }
665                      }
666                  }
667 +                if (validated)
668 +                    break;
669              }
670              else if (e.hash < 0)
671                  tab = (Node[])e.key;
672 +            else if (!replace && e.hash == h && (ev = e.val) != null &&
673 +                     ((ek = e.key) == k || k.equals(ek))) {
674 +                if (tabAt(tab, i) == e) {
675 +                    val = (V)ev;
676 +                    break;
677 +                }
678 +            }
679              else if (Thread.holdsLock(e))
680                  throw new IllegalStateException("Recursive map computation");
681              else {
682 +                boolean validated = false;
683                  boolean checkSize = false;
684                  synchronized (e) {
685 <                    Node first = e;
686 <                    for (;;) {
687 <                        Object ek, ev;
688 <                        if ((ev = e.val) == null)
689 <                            break;
690 <                        if (e.hash == h && (ek = e.key) != null &&
691 <                            (k == ek || k.equals(ek))) {
692 <                            if (tabAt(tab, i) == first) {
693 <                                validated = true;
536 <                                if (replace && (ev = f.map(k)) != null)
537 <                                    e.val = ev;
685 >                    if (tabAt(tab, i) == e) {
686 >                        validated = true;
687 >                        for (Node first = e;;) {
688 >                            if (e.hash == h &&
689 >                                ((ek = e.key) == k || k.equals(ek)) &&
690 >                                ((ev = e.val) != null)) {
691 >                                Object fv;
692 >                                if (replace && (fv = f.map(k)) != null)
693 >                                    ev = e.val = fv;
694                                  val = (V)ev;
695 +                                break;
696                              }
697 <                            break;
698 <                        }
542 <                        Node last = e;
543 <                        if ((e = e.next) == null) {
544 <                            if (tabAt(tab, i) == first) {
545 <                                validated = true;
697 >                            Node last = e;
698 >                            if ((e = e.next) == null) {
699                                  if ((val = f.map(k)) != null) {
700                                      last.next = new Node(h, k, val, null);
701                                      added = true;
702                                      if (last != first || tab.length <= 64)
703                                          checkSize = true;
704                                  }
705 +                                break;
706                              }
553                            break;
707                          }
708                      }
709                  }
710 <                if (checkSize && tab.length < MAXIMUM_CAPACITY &&
711 <                    resizing == 0 && counter.sum() >= threshold)
712 <                    grow(0);
710 >                if (validated) {
711 >                    if (checkSize && tab.length < MAXIMUM_CAPACITY &&
712 >                        resizing == 0 && counter.sum() >= (long)threshold)
713 >                        growTable();
714 >                    break;
715 >                }
716              }
717 <        } while (!validated);
717 >        }
718          if (added)
719              counter.increment();
720          return val;
721      }
722  
567    /*
568     * Reclassifies nodes in each bin to new table.  Because we are
569     * using power-of-two expansion, the elements from each bin must
570     * either stay at same index, or move with a power of two
571     * offset. We eliminate unnecessary node creation by catching
572     * cases where old nodes can be reused because their next fields
573     * won't change.  Statistically, at the default threshold, only
574     * about one-sixth of them need cloning when a table doubles. The
575     * nodes they replace will be garbage collectable as soon as they
576     * are no longer referenced by any reader thread that may be in
577     * the midst of concurrently traversing table.
578     *
579     * Transfers are done from the bottom up to preserve iterator
580     * traversability. On each step, the old bin is locked,
581     * moved/copied, and then replaced with a forwarding node.
582     */
583    private static final void transfer(Node[] tab, Node[] nextTab) {
584        int n = tab.length;
585        int mask = nextTab.length - 1;
586        Node fwd = new Node(MOVED, nextTab, null, null);
587        for (int i = n - 1; i >= 0; --i) {
588            for (Node e;;) {
589                if ((e = tabAt(tab, i)) == null) {
590                    if (casTabAt(tab, i, e, fwd))
591                        break;
592                }
593                else {
594                    boolean validated = false;
595                    synchronized (e) {
596                        int idx = e.hash & mask;
597                        Node lastRun = e;
598                        for (Node p = e.next; p != null; p = p.next) {
599                            int j = p.hash & mask;
600                            if (j != idx) {
601                                idx = j;
602                                lastRun = p;
603                            }
604                        }
605                        if (tabAt(tab, i) == e) {
606                            validated = true;
607                            relaxedSetTabAt(nextTab, idx, lastRun);
608                            for (Node p = e; p != lastRun; p = p.next) {
609                                int h = p.hash;
610                                int j = h & mask;
611                                Node r = relaxedTabAt(nextTab, j);
612                                relaxedSetTabAt(nextTab, j,
613                                                new Node(h, p.key, p.val, r));
614                            }
615                            setTabAt(tab, i, fwd);
616                        }
617                    }
618                    if (validated)
619                        break;
620                }
621            }
622        }
623    }
624
625    /**
626     * If not already resizing, initializes or creates next table and
627     * transfers bins. Rechecks occupancy after a transfer to see if
628     * another resize is already needed because resizings are lagging
629     * additions.
630     *
631     * @param sizeHint overridden capacity target (nonzero only from putAll)
632     * @return current table
633     */
634    private final Node[] grow(int sizeHint) {
635        if (resizing == 0 &&
636            UNSAFE.compareAndSwapInt(this, resizingOffset, 0, 1)) {
637            try {
638                for (;;) {
639                    int cap, n;
640                    Node[] tab = table;
641                    if (tab == null) {
642                        int c = initCap;
643                        if (c < sizeHint)
644                            c = sizeHint;
645                        if (c == DEFAULT_CAPACITY)
646                            cap = c;
647                        else if (c >= MAXIMUM_CAPACITY)
648                            cap = MAXIMUM_CAPACITY;
649                        else {
650                            cap = MINIMUM_CAPACITY;
651                            while (cap < c)
652                                cap <<= 1;
653                        }
654                    }
655                    else if ((n = tab.length) < MAXIMUM_CAPACITY &&
656                             (sizeHint <= 0 || n < sizeHint))
657                        cap = n << 1;
658                    else
659                        break;
660                    threshold = (int)(cap * loadFactor) - THRESHOLD_OFFSET;
661                    Node[] nextTab = new Node[cap];
662                    if (tab != null)
663                        transfer(tab, nextTab);
664                    table = nextTab;
665                    if (tab == null || cap >= MAXIMUM_CAPACITY ||
666                        (sizeHint > 0 && cap >= sizeHint) ||
667                        counter.sum() < threshold)
668                        break;
669                }
670            } finally {
671                resizing = 0;
672            }
673        }
674        else if (table == null)
675            Thread.yield(); // lost initialization race; just spin
676        return table;
677    }
678
679    /**
680     * Implementation for putAll and constructor with Map
681     * argument. Tries to first override initial capacity or grow
682     * based on map size to pre-allocate table space.
683     */
684    private final void internalPutAll(Map<? extends K, ? extends V> m) {
685        int s = m.size();
686        grow((s >= (MAXIMUM_CAPACITY >>> 1)) ? s : s + (s >>> 1));
687        for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
688            Object k = e.getKey();
689            Object v = e.getValue();
690            if (k == null || v == null)
691                throw new NullPointerException();
692            internalPut(k, v, true);
693        }
694    }
695
723      /**
724       * Implementation for clear. Steps through each bin, removing all nodes.
725       */
726      private final void internalClear() {
727 <        long deletions = 0L;
727 >        long delta = 0L; // negative number of deletions
728          int i = 0;
729          Node[] tab = table;
730          while (tab != null && i < tab.length) {
# Line 711 | Line 738 | public class ConcurrentHashMapV8<K, V>
738                  synchronized (e) {
739                      if (tabAt(tab, i) == e) {
740                          validated = true;
741 +                        Node en;
742                          do {
743 <                            if (e.val != null) {
743 >                            en = e.next;
744 >                            if (e.val != null) { // currently always true
745                                  e.val = null;
746 <                                ++deletions;
746 >                                --delta;
747                              }
748 <                        } while ((e = e.next) != null);
748 >                        } while ((e = en) != null);
749                          setTabAt(tab, i, null);
750                      }
751                  }
752 <                if (validated) {
752 >                if (validated)
753                      ++i;
725                    if (deletions > THRESHOLD_OFFSET) { // bound lag in counts
726                        counter.add(-deletions);
727                        deletions = 0L;
728                    }
729                }
754              }
755          }
756 <        if (deletions != 0L)
733 <            counter.add(-deletions);
756 >        counter.add(delta);
757      }
758  
759 <    /**
737 <     * Base class for key, value, and entry iterators, plus internal
738 <     * implementations of public traversal-based methods, to avoid
739 <     * duplicating traversal code.
740 <     */
741 <    class HashIterator {
742 <        private Node next;          // the next entry to return
743 <        private Node[] tab;         // current table; updated if resized
744 <        private Node lastReturned;  // the last entry returned, for remove
745 <        private Object nextVal;     // cached value of next
746 <        private int index;          // index of bin to use next
747 <        private int baseIndex;      // current index of initial table
748 <        private final int baseSize; // initial table size
749 <
750 <        HashIterator() {
751 <            Node[] t = tab = table;
752 <            if (t == null)
753 <                baseSize = 0;
754 <            else {
755 <                baseSize = t.length;
756 <                advance(null);
757 <            }
758 <        }
759 <
760 <        public final boolean hasNext()         { return next != null; }
761 <        public final boolean hasMoreElements() { return next != null; }
759 >    /* ----------------Table Traversal -------------- */
760  
761 <        /**
762 <         * Advances next.  Normally, iteration proceeds bin-by-bin
763 <         * traversing lists.  However, if the table has been resized,
764 <         * then all future steps must traverse both the bin at the
765 <         * current index as well as at (index + baseSize); and so on
766 <         * for further resizings. To paranoically cope with potential
767 <         * (improper) sharing of iterators across threads, table reads
768 <         * are bounds-checked.
769 <         */
770 <        final void advance(Node e) {
771 <            for (;;) {
772 <                Node[] t; int i; // for bounds checks
773 <                if (e != null) {
774 <                    Object ek = e.key, ev = e.val;
775 <                    if (ev != null && ek != null) {
776 <                        nextVal = ev;
777 <                        next = e;
778 <                        break;
779 <                    }
761 >    /**
762 >     * Encapsulates traversal for methods such as containsValue; also
763 >     * serves as a base class for other iterators.
764 >     *
765 >     * At each step, the iterator snapshots the key ("nextKey") and
766 >     * value ("nextVal") of a valid node (i.e., one that, at point of
767 >     * snapshot, has a nonnull user value). Because val fields can
768 >     * change (including to null, indicating deletion), field nextVal
769 >     * might not be accurate at point of use, but still maintains the
770 >     * weak consistency property of holding a value that was once
771 >     * valid.
772 >     *
773 >     * Internal traversals directly access these fields, as in:
774 >     * {@code while (it.next != null) { process(nextKey); it.advance(); }}
775 >     *
776 >     * Exported iterators (subclasses of ViewIterator) extract key,
777 >     * value, or key-value pairs as return values of Iterator.next(),
778 >     * and encapsulate the it.next check as hasNext();
779 >     *
780 >     * The iterator visits each valid node that was reachable upon
781 >     * iterator construction once. It might miss some that were added
782 >     * to a bin after the bin was visited, which is OK wrt consistency
783 >     * guarantees. Maintaining this property in the face of possible
784 >     * ongoing resizes requires a fair amount of bookkeeping state
785 >     * that is difficult to optimize away amidst volatile accesses.
786 >     * Even so, traversal maintains reasonable throughput.
787 >     *
788 >     * Normally, iteration proceeds bin-by-bin traversing lists.
789 >     * However, if the table has been resized, then all future steps
790 >     * must traverse both the bin at the current index as well as at
791 >     * (index + baseSize); and so on for further resizings. To
792 >     * paranoically cope with potential sharing by users of iterators
793 >     * across threads, iteration terminates if a bounds checks fails
794 >     * for a table read.
795 >     *
796 >     * The range-based constructor enables creation of parallel
797 >     * range-splitting traversals. (Not yet implemented.)
798 >     */
799 >    static class InternalIterator {
800 >        Node next;           // the next entry to use
801 >        Node last;           // the last entry used
802 >        Object nextKey;      // cached key field of next
803 >        Object nextVal;      // cached val field of next
804 >        Node[] tab;          // current table; updated if resized
805 >        int index;           // index of bin to use next
806 >        int baseIndex;       // current index of initial table
807 >        final int baseLimit; // index bound for initial table
808 >        final int baseSize;  // initial table size
809 >
810 >        /** Creates iterator for all entries in the table. */
811 >        InternalIterator(Node[] tab) {
812 >            this.tab = tab;
813 >            baseLimit = baseSize = (tab == null) ? 0 : tab.length;
814 >            index = baseIndex = 0;
815 >            next = null;
816 >            advance();
817 >        }
818 >
819 >        /** Creates iterator for the given range of the table */
820 >        InternalIterator(Node[] tab, int lo, int hi) {
821 >            this.tab = tab;
822 >            baseSize = (tab == null) ? 0 : tab.length;
823 >            baseLimit = (hi <= baseSize) ? hi : baseSize;
824 >            index = baseIndex = lo;
825 >            next = null;
826 >            advance();
827 >        }
828 >
829 >        /** Advances next. See above for explanation. */
830 >        final void advance() {
831 >            Node e = last = next;
832 >            outer: do {
833 >                if (e != null)                   // pass used or skipped node
834                      e = e.next;
835 +                while (e == null) {              // get to next non-null bin
836 +                    Node[] t; int b, i, n;       // checks must use locals
837 +                    if ((b = baseIndex) >= baseLimit || (i = index) < 0 ||
838 +                        (t = tab) == null || i >= (n = t.length))
839 +                        break outer;
840 +                    else if ((e = tabAt(t, i)) != null && e.hash < 0)
841 +                        tab = (Node[])e.key;     // restarts due to null val
842 +                    else                         // visit upper slots if present
843 +                        index = (i += baseSize) < n ? i : (baseIndex = b + 1);
844                  }
845 <                else if (baseIndex < baseSize && (t = tab) != null &&
846 <                         t.length > (i = index) && i >= 0) {
847 <                    if ((e = tabAt(t, i)) != null && e.hash < 0) {
787 <                        tab = (Node[])e.key;
788 <                        e = null;
789 <                    }
790 <                    else if (i + baseSize < t.length)
791 <                        index += baseSize;    // visit forwarded upper slots
792 <                    else
793 <                        index = ++baseIndex;
794 <                }
795 <                else {
796 <                    next = null;
797 <                    break;
798 <                }
799 <            }
800 <        }
801 <
802 <        final Object nextKey() {
803 <            Node e = next;
804 <            if (e == null)
805 <                throw new NoSuchElementException();
806 <            Object k = e.key;
807 <            advance((lastReturned = e).next);
808 <            return k;
809 <        }
810 <
811 <        final Object nextValue() {
812 <            Node e = next;
813 <            if (e == null)
814 <                throw new NoSuchElementException();
815 <            Object v = nextVal;
816 <            advance((lastReturned = e).next);
817 <            return v;
818 <        }
819 <
820 <        final WriteThroughEntry nextEntry() {
821 <            Node e = next;
822 <            if (e == null)
823 <                throw new NoSuchElementException();
824 <            WriteThroughEntry entry =
825 <                new WriteThroughEntry(e.key, nextVal);
826 <            advance((lastReturned = e).next);
827 <            return entry;
828 <        }
829 <
830 <        public final void remove() {
831 <            if (lastReturned == null)
832 <                throw new IllegalStateException();
833 <            ConcurrentHashMapV8.this.remove(lastReturned.key);
834 <            lastReturned = null;
835 <        }
836 <
837 <        /** Helper for serialization */
838 <        final void writeEntries(java.io.ObjectOutputStream s)
839 <            throws java.io.IOException {
840 <            Node e;
841 <            while ((e = next) != null) {
842 <                s.writeObject(e.key);
843 <                s.writeObject(nextVal);
844 <                advance(e.next);
845 <            }
846 <        }
847 <
848 <        /** Helper for containsValue */
849 <        final boolean containsVal(Object value) {
850 <            if (value != null) {
851 <                Node e;
852 <                while ((e = next) != null) {
853 <                    Object v = nextVal;
854 <                    if (value == v || value.equals(v))
855 <                        return true;
856 <                    advance(e.next);
857 <                }
858 <            }
859 <            return false;
860 <        }
861 <
862 <        /** Helper for Map.hashCode */
863 <        final int mapHashCode() {
864 <            int h = 0;
865 <            Node e;
866 <            while ((e = next) != null) {
867 <                h += e.key.hashCode() ^ nextVal.hashCode();
868 <                advance(e.next);
869 <            }
870 <            return h;
871 <        }
872 <
873 <        /** Helper for Map.toString */
874 <        final String mapToString() {
875 <            Node e = next;
876 <            if (e == null)
877 <                return "{}";
878 <            StringBuilder sb = new StringBuilder();
879 <            sb.append('{');
880 <            for (;;) {
881 <                sb.append(e.key   == this ? "(this Map)" : e.key);
882 <                sb.append('=');
883 <                sb.append(nextVal == this ? "(this Map)" : nextVal);
884 <                advance(e.next);
885 <                if ((e = next) != null)
886 <                    sb.append(',').append(' ');
887 <                else
888 <                    return sb.append('}').toString();
889 <            }
845 >                nextKey = e.key;
846 >            } while ((nextVal = e.val) == null); // skip deleted or special nodes
847 >            next = e;
848          }
849      }
850  
851      /* ---------------- Public operations -------------- */
852  
853      /**
854 <     * Creates a new, empty map with the specified initial
897 <     * capacity, load factor and concurrency level.
898 <     *
899 <     * @param initialCapacity the initial capacity. The implementation
900 <     * performs internal sizing to accommodate this many elements.
901 <     * @param loadFactor  the load factor threshold, used to control resizing.
902 <     * Resizing may be performed when the average number of elements per
903 <     * bin exceeds this threshold.
904 <     * @param concurrencyLevel the estimated number of concurrently
905 <     * updating threads. The implementation may use this value as
906 <     * a sizing hint.
907 <     * @throws IllegalArgumentException if the initial capacity is
908 <     * negative or the load factor or concurrencyLevel are
909 <     * nonpositive.
854 >     * Creates a new, empty map with the default initial table size (16),
855       */
856 <    public ConcurrentHashMapV8(int initialCapacity,
912 <                             float loadFactor, int concurrencyLevel) {
913 <        if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
914 <            throw new IllegalArgumentException();
915 <        this.initCap = initialCapacity;
916 <        this.loadFactor = loadFactor;
856 >    public ConcurrentHashMapV8() {
857          this.counter = new LongAdder();
858 +        this.targetCapacity = DEFAULT_CAPACITY;
859      }
860  
861      /**
862 <     * Creates a new, empty map with the specified initial capacity
863 <     * and load factor and with the default concurrencyLevel (16).
862 >     * Creates a new, empty map with an initial table size
863 >     * accommodating the specified number of elements without the need
864 >     * to dynamically resize.
865       *
866       * @param initialCapacity The implementation performs internal
867       * sizing to accommodate this many elements.
926     * @param loadFactor  the load factor threshold, used to control resizing.
927     * Resizing may be performed when the average number of elements per
928     * bin exceeds this threshold.
868       * @throws IllegalArgumentException if the initial capacity of
869 <     * elements is negative or the load factor is nonpositive
931 <     *
932 <     * @since 1.6
869 >     * elements is negative
870       */
871 <    public ConcurrentHashMapV8(int initialCapacity, float loadFactor) {
872 <        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
871 >    public ConcurrentHashMapV8(int initialCapacity) {
872 >        if (initialCapacity < 0)
873 >            throw new IllegalArgumentException();
874 >        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
875 >                   MAXIMUM_CAPACITY :
876 >                   tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
877 >        this.counter = new LongAdder();
878 >        this.targetCapacity = cap;
879      }
880  
881      /**
882 <     * Creates a new, empty map with the specified initial capacity,
940 <     * and with default load factor (0.75) and concurrencyLevel (16).
882 >     * Creates a new map with the same mappings as the given map.
883       *
884 <     * @param initialCapacity the initial capacity. The implementation
943 <     * performs internal sizing to accommodate this many elements.
944 <     * @throws IllegalArgumentException if the initial capacity of
945 <     * elements is negative.
884 >     * @param m the map
885       */
886 <    public ConcurrentHashMapV8(int initialCapacity) {
887 <        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
886 >    public ConcurrentHashMapV8(Map<? extends K, ? extends V> m) {
887 >        this.counter = new LongAdder();
888 >        this.targetCapacity = DEFAULT_CAPACITY;
889 >        putAll(m);
890      }
891  
892      /**
893 <     * Creates a new, empty map with a default initial capacity (16),
894 <     * load factor (0.75) and concurrencyLevel (16).
893 >     * Creates a new, empty map with an initial table size based on
894 >     * the given number of elements ({@code initialCapacity}) and
895 >     * initial table density ({@code loadFactor}).
896 >     *
897 >     * @param initialCapacity the initial capacity. The implementation
898 >     * performs internal sizing to accommodate this many elements,
899 >     * given the specified load factor.
900 >     * @param loadFactor the load factor (table density) for
901 >     * establishing the initial table size
902 >     * @throws IllegalArgumentException if the initial capacity of
903 >     * elements is negative or the load factor is nonpositive
904 >     *
905 >     * @since 1.6
906       */
907 <    public ConcurrentHashMapV8() {
908 <        this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
907 >    public ConcurrentHashMapV8(int initialCapacity, float loadFactor) {
908 >        this(initialCapacity, loadFactor, 1);
909      }
910  
911      /**
912 <     * Creates a new map with the same mappings as the given map.
913 <     * The map is created with a capacity of 1.5 times the number
914 <     * of mappings in the given map or 16 (whichever is greater),
915 <     * and a default load factor (0.75) and concurrencyLevel (16).
912 >     * Creates a new, empty map with an initial table size based on
913 >     * the given number of elements ({@code initialCapacity}), table
914 >     * density ({@code loadFactor}), and number of concurrently
915 >     * updating threads ({@code concurrencyLevel}).
916       *
917 <     * @param m the map
917 >     * @param initialCapacity the initial capacity. The implementation
918 >     * performs internal sizing to accommodate this many elements,
919 >     * given the specified load factor.
920 >     * @param loadFactor the load factor (table density) for
921 >     * establishing the initial table size
922 >     * @param concurrencyLevel the estimated number of concurrently
923 >     * updating threads. The implementation may use this value as
924 >     * a sizing hint.
925 >     * @throws IllegalArgumentException if the initial capacity is
926 >     * negative or the load factor or concurrencyLevel are
927 >     * nonpositive
928       */
929 <    public ConcurrentHashMapV8(Map<? extends K, ? extends V> m) {
930 <        this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
931 <        if (m == null)
932 <            throw new NullPointerException();
933 <        internalPutAll(m);
929 >    public ConcurrentHashMapV8(int initialCapacity,
930 >                               float loadFactor, int concurrencyLevel) {
931 >        if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
932 >            throw new IllegalArgumentException();
933 >        if (initialCapacity < concurrencyLevel)   // Use at least as many bins
934 >            initialCapacity = concurrencyLevel;   // as estimated threads
935 >        long size = (long)(1.0 + (long)initialCapacity / loadFactor);
936 >        int cap =  ((size >= (long)MAXIMUM_CAPACITY) ?
937 >                    MAXIMUM_CAPACITY: tableSizeFor((int)size));
938 >        this.counter = new LongAdder();
939 >        this.targetCapacity = cap;
940      }
941  
942      /**
943 <     * Returns {@code true} if this map contains no key-value mappings.
976 <     *
977 <     * @return {@code true} if this map contains no key-value mappings
943 >     * {@inheritDoc}
944       */
945      public boolean isEmpty() {
946          return counter.sum() <= 0L; // ignore transient negative values
947      }
948  
949      /**
950 <     * Returns the number of key-value mappings in this map.  If the
985 <     * map contains more than {@code Integer.MAX_VALUE} elements, returns
986 <     * {@code Integer.MAX_VALUE}.
987 <     *
988 <     * @return the number of key-value mappings in this map
950 >     * {@inheritDoc}
951       */
952      public int size() {
953          long n = counter.sum();
954 <        return ((n >>> 31) == 0) ? (int)n : (n < 0L) ? 0 : Integer.MAX_VALUE;
954 >        return ((n < 0L) ? 0 :
955 >                (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE :
956 >                (int)n);
957      }
958  
959      /**
# Line 1016 | Line 980 | public class ConcurrentHashMapV8<K, V>
980       * @param  key   possible key
981       * @return {@code true} if and only if the specified object
982       *         is a key in this table, as determined by the
983 <     *         {@code equals} method; {@code false} otherwise.
983 >     *         {@code equals} method; {@code false} otherwise
984       * @throws NullPointerException if the specified key is null
985       */
986      public boolean containsKey(Object key) {
# Line 1027 | Line 991 | public class ConcurrentHashMapV8<K, V>
991  
992      /**
993       * Returns {@code true} if this map maps one or more keys to the
994 <     * specified value. Note: This method requires a full internal
995 <     * traversal of the hash table, and so is much slower than
1032 <     * method {@code containsKey}.
994 >     * specified value. Note: This method may require a full traversal
995 >     * of the map, and is much slower than method {@code containsKey}.
996       *
997       * @param value value whose presence in this map is to be tested
998       * @return {@code true} if this map maps one or more keys to the
# Line 1039 | Line 1002 | public class ConcurrentHashMapV8<K, V>
1002      public boolean containsValue(Object value) {
1003          if (value == null)
1004              throw new NullPointerException();
1005 <        return new HashIterator().containsVal(value);
1005 >        Object v;
1006 >        InternalIterator it = new InternalIterator(table);
1007 >        while (it.next != null) {
1008 >            if ((v = it.nextVal) == value || value.equals(v))
1009 >                return true;
1010 >            it.advance();
1011 >        }
1012 >        return false;
1013      }
1014  
1015      /**
# Line 1105 | Line 1075 | public class ConcurrentHashMapV8<K, V>
1075      public void putAll(Map<? extends K, ? extends V> m) {
1076          if (m == null)
1077              throw new NullPointerException();
1078 <        internalPutAll(m);
1078 >        /*
1079 >         * If uninitialized, try to adjust targetCapacity to
1080 >         * accommodate the given number of elements.
1081 >         */
1082 >        if (table == null) {
1083 >            int size = m.size();
1084 >            int cap = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
1085 >                tableSizeFor(size + (size >>> 1) + 1);
1086 >            if (cap > targetCapacity)
1087 >                targetCapacity = cap;
1088 >        }
1089 >        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
1090 >            put(e.getKey(), e.getValue());
1091      }
1092  
1093      /**
1094       * If the specified key is not already associated with a value,
1095       * computes its value using the given mappingFunction, and if
1096       * non-null, enters it into the map.  This is equivalent to
1097 <     *
1098 <     * <pre>
1099 <     *   if (map.containsKey(key))
1100 <     *       return map.get(key);
1101 <     *   value = mappingFunction.map(key);
1102 <     *   if (value != null)
1103 <     *      map.put(key, value);
1122 <     *   return value;
1123 <     * </pre>
1097 >     *  <pre> {@code
1098 >     * if (map.containsKey(key))
1099 >     *   return map.get(key);
1100 >     * value = mappingFunction.map(key);
1101 >     * if (value != null)
1102 >     *   map.put(key, value);
1103 >     * return value;}</pre>
1104       *
1105       * except that the action is performed atomically.  Some attempted
1106       * update operations on this map by other threads may be blocked
# Line 1129 | Line 1109 | public class ConcurrentHashMapV8<K, V>
1109       * mappings of this Map. The most appropriate usage is to
1110       * construct a new object serving as an initial mapped value, or
1111       * memoized result, as in:
1112 <     * <pre>{@code
1112 >     *  <pre> {@code
1113       * map.computeIfAbsent(key, new MappingFunction<K, V>() {
1114 <     *   public V map(K k) { return new Value(f(k)); }};
1135 <     * }</pre>
1114 >     *   public V map(K k) { return new Value(f(k)); }});}</pre>
1115       *
1116       * @param key key with which the specified value is to be associated
1117       * @param mappingFunction the function to compute a value
1118       * @return the current (existing or computed) value associated with
1119       *         the specified key, or {@code null} if the computation
1120 <     *         returned {@code null}.
1120 >     *         returned {@code null}
1121       * @throws NullPointerException if the specified key or mappingFunction
1122 <     *         is null,
1122 >     *         is null
1123       * @throws IllegalStateException if the computation detectably
1124       *         attempts a recursive update to this map that would
1125 <     *         otherwise never complete.
1125 >     *         otherwise never complete
1126       * @throws RuntimeException or Error if the mappingFunction does so,
1127 <     *         in which case the mapping is left unestablished.
1127 >     *         in which case the mapping is left unestablished
1128       */
1129      public V computeIfAbsent(K key, MappingFunction<? super K, ? extends V> mappingFunction) {
1130          if (key == null || mappingFunction == null)
# Line 1157 | Line 1136 | public class ConcurrentHashMapV8<K, V>
1136       * Computes the value associated with the given key using the given
1137       * mappingFunction, and if non-null, enters it into the map.  This
1138       * is equivalent to
1139 <     *
1140 <     * <pre>
1141 <     *   value = mappingFunction.map(key);
1142 <     *   if (value != null)
1143 <     *      map.put(key, value);
1144 <     *   else
1145 <     *      value = map.get(key);
1167 <     *   return value;
1168 <     * </pre>
1139 >     *  <pre> {@code
1140 >     * value = mappingFunction.map(key);
1141 >     * if (value != null)
1142 >     *   map.put(key, value);
1143 >     * else
1144 >     *   value = map.get(key);
1145 >     * return value;}</pre>
1146       *
1147       * except that the action is performed atomically.  Some attempted
1148       * update operations on this map by other threads may be blocked
# Line 1177 | Line 1154 | public class ConcurrentHashMapV8<K, V>
1154       * @param mappingFunction the function to compute a value
1155       * @return the current value associated with
1156       *         the specified key, or {@code null} if the computation
1157 <     *         returned {@code null} and the value was not otherwise present.
1157 >     *         returned {@code null} and the value was not otherwise present
1158       * @throws NullPointerException if the specified key or mappingFunction
1159 <     *         is null,
1159 >     *         is null
1160       * @throws IllegalStateException if the computation detectably
1161       *         attempts a recursive update to this map that would
1162 <     *         otherwise never complete.
1162 >     *         otherwise never complete
1163       * @throws RuntimeException or Error if the mappingFunction does so,
1164 <     *         in which case the mapping is unchanged.
1164 >     *         in which case the mapping is unchanged
1165       */
1166      public V compute(K key, MappingFunction<? super K, ? extends V> mappingFunction) {
1167          if (key == null || mappingFunction == null)
# Line 1270 | Line 1247 | public class ConcurrentHashMapV8<K, V>
1247       * reflect any modifications subsequent to construction.
1248       */
1249      public Set<K> keySet() {
1250 <        Set<K> ks = keySet;
1251 <        return (ks != null) ? ks : (keySet = new KeySet());
1250 >        KeySet<K,V> ks = keySet;
1251 >        return (ks != null) ? ks : (keySet = new KeySet<K,V>(this));
1252      }
1253  
1254      /**
# Line 1291 | Line 1268 | public class ConcurrentHashMapV8<K, V>
1268       * reflect any modifications subsequent to construction.
1269       */
1270      public Collection<V> values() {
1271 <        Collection<V> vs = values;
1272 <        return (vs != null) ? vs : (values = new Values());
1271 >        Values<K,V> vs = values;
1272 >        return (vs != null) ? vs : (values = new Values<K,V>(this));
1273      }
1274  
1275      /**
# Line 1312 | Line 1289 | public class ConcurrentHashMapV8<K, V>
1289       * reflect any modifications subsequent to construction.
1290       */
1291      public Set<Map.Entry<K,V>> entrySet() {
1292 <        Set<Map.Entry<K,V>> es = entrySet;
1293 <        return (es != null) ? es : (entrySet = new EntrySet());
1292 >        EntrySet<K,V> es = entrySet;
1293 >        return (es != null) ? es : (entrySet = new EntrySet<K,V>(this));
1294      }
1295  
1296      /**
# Line 1323 | Line 1300 | public class ConcurrentHashMapV8<K, V>
1300       * @see #keySet()
1301       */
1302      public Enumeration<K> keys() {
1303 <        return new KeyIterator();
1303 >        return new KeyIterator<K,V>(this);
1304      }
1305  
1306      /**
# Line 1333 | Line 1310 | public class ConcurrentHashMapV8<K, V>
1310       * @see #values()
1311       */
1312      public Enumeration<V> elements() {
1313 <        return new ValueIterator();
1313 >        return new ValueIterator<K,V>(this);
1314      }
1315  
1316      /**
# Line 1344 | Line 1321 | public class ConcurrentHashMapV8<K, V>
1321       * @return the hash code value for this map
1322       */
1323      public int hashCode() {
1324 <        return new HashIterator().mapHashCode();
1324 >        int h = 0;
1325 >        InternalIterator it = new InternalIterator(table);
1326 >        while (it.next != null) {
1327 >            h += it.nextKey.hashCode() ^ it.nextVal.hashCode();
1328 >            it.advance();
1329 >        }
1330 >        return h;
1331      }
1332  
1333      /**
# Line 1359 | Line 1342 | public class ConcurrentHashMapV8<K, V>
1342       * @return a string representation of this map
1343       */
1344      public String toString() {
1345 <        return new HashIterator().mapToString();
1345 >        InternalIterator it = new InternalIterator(table);
1346 >        StringBuilder sb = new StringBuilder();
1347 >        sb.append('{');
1348 >        if (it.next != null) {
1349 >            for (;;) {
1350 >                Object k = it.nextKey, v = it.nextVal;
1351 >                sb.append(k == this ? "(this Map)" : k);
1352 >                sb.append('=');
1353 >                sb.append(v == this ? "(this Map)" : v);
1354 >                it.advance();
1355 >                if (it.next == null)
1356 >                    break;
1357 >                sb.append(',').append(' ');
1358 >            }
1359 >        }
1360 >        return sb.append('}').toString();
1361      }
1362  
1363      /**
# Line 1373 | Line 1371 | public class ConcurrentHashMapV8<K, V>
1371       * @return {@code true} if the specified object is equal to this map
1372       */
1373      public boolean equals(Object o) {
1374 <        if (o == this)
1375 <            return true;
1376 <        if (!(o instanceof Map))
1377 <            return false;
1378 <        Map<?,?> m = (Map<?,?>) o;
1379 <        try {
1380 <            for (Map.Entry<K,V> e : this.entrySet())
1381 <                if (! e.getValue().equals(m.get(e.getKey())))
1374 >        if (o != this) {
1375 >            if (!(o instanceof Map))
1376 >                return false;
1377 >            Map<?,?> m = (Map<?,?>) o;
1378 >            InternalIterator it = new InternalIterator(table);
1379 >            while (it.next != null) {
1380 >                Object val = it.nextVal;
1381 >                Object v = m.get(it.nextKey);
1382 >                if (v == null || (v != val && !v.equals(val)))
1383                      return false;
1384 +                it.advance();
1385 +            }
1386              for (Map.Entry<?,?> e : m.entrySet()) {
1387 <                Object k = e.getKey();
1388 <                Object v = e.getValue();
1389 <                if (k == null || v == null || !v.equals(get(k)))
1387 >                Object mk, mv, v;
1388 >                if ((mk = e.getKey()) == null ||
1389 >                    (mv = e.getValue()) == null ||
1390 >                    (v = internalGet(mk)) == null ||
1391 >                    (mv != v && !mv.equals(v)))
1392                      return false;
1393              }
1394 <            return true;
1395 <        } catch (ClassCastException unused) {
1396 <            return false;
1397 <        } catch (NullPointerException unused) {
1398 <            return false;
1394 >        }
1395 >        return true;
1396 >    }
1397 >
1398 >    /* ----------------Iterators -------------- */
1399 >
1400 >    /**
1401 >     * Base class for key, value, and entry iterators.  Adds a map
1402 >     * reference to InternalIterator to support Iterator.remove.
1403 >     */
1404 >    static abstract class ViewIterator<K,V> extends InternalIterator {
1405 >        final ConcurrentHashMapV8<K, V> map;
1406 >        ViewIterator(ConcurrentHashMapV8<K, V> map) {
1407 >            super(map.table);
1408 >            this.map = map;
1409 >        }
1410 >
1411 >        public final void remove() {
1412 >            if (last == null)
1413 >                throw new IllegalStateException();
1414 >            map.remove(last.key);
1415 >            last = null;
1416 >        }
1417 >
1418 >        public final boolean hasNext()         { return next != null; }
1419 >        public final boolean hasMoreElements() { return next != null; }
1420 >    }
1421 >
1422 >    static final class KeyIterator<K,V> extends ViewIterator<K,V>
1423 >        implements Iterator<K>, Enumeration<K> {
1424 >        KeyIterator(ConcurrentHashMapV8<K, V> map) { super(map); }
1425 >
1426 >        @SuppressWarnings("unchecked")
1427 >        public final K next() {
1428 >            if (next == null)
1429 >                throw new NoSuchElementException();
1430 >            Object k = nextKey;
1431 >            advance();
1432 >            return (K)k;
1433 >        }
1434 >
1435 >        public final K nextElement() { return next(); }
1436 >    }
1437 >
1438 >    static final class ValueIterator<K,V> extends ViewIterator<K,V>
1439 >        implements Iterator<V>, Enumeration<V> {
1440 >        ValueIterator(ConcurrentHashMapV8<K, V> map) { super(map); }
1441 >
1442 >        @SuppressWarnings("unchecked")
1443 >        public final V next() {
1444 >            if (next == null)
1445 >                throw new NoSuchElementException();
1446 >            Object v = nextVal;
1447 >            advance();
1448 >            return (V)v;
1449 >        }
1450 >
1451 >        public final V nextElement() { return next(); }
1452 >    }
1453 >
1454 >    static final class EntryIterator<K,V> extends ViewIterator<K,V>
1455 >        implements Iterator<Map.Entry<K,V>> {
1456 >        EntryIterator(ConcurrentHashMapV8<K, V> map) { super(map); }
1457 >
1458 >        @SuppressWarnings("unchecked")
1459 >        public final Map.Entry<K,V> next() {
1460 >            if (next == null)
1461 >                throw new NoSuchElementException();
1462 >            Object k = nextKey;
1463 >            Object v = nextVal;
1464 >            advance();
1465 >            return new WriteThroughEntry<K,V>(map, (K)k, (V)v);
1466          }
1467      }
1468  
# Line 1400 | Line 1470 | public class ConcurrentHashMapV8<K, V>
1470       * Custom Entry class used by EntryIterator.next(), that relays
1471       * setValue changes to the underlying map.
1472       */
1473 <    final class WriteThroughEntry extends AbstractMap.SimpleEntry<K,V> {
1474 <        @SuppressWarnings("unchecked")
1475 <        WriteThroughEntry(Object k, Object v) {
1476 <            super((K)k, (V)v);
1473 >    static final class WriteThroughEntry<K,V> implements Map.Entry<K, V> {
1474 >        final ConcurrentHashMapV8<K, V> map;
1475 >        final K key; // non-null
1476 >        V val;       // non-null
1477 >        WriteThroughEntry(ConcurrentHashMapV8<K, V> map, K key, V val) {
1478 >            this.map = map; this.key = key; this.val = val;
1479 >        }
1480 >
1481 >        public final K getKey()       { return key; }
1482 >        public final V getValue()     { return val; }
1483 >        public final int hashCode()   { return key.hashCode() ^ val.hashCode(); }
1484 >        public final String toString(){ return key + "=" + val; }
1485 >
1486 >        public final boolean equals(Object o) {
1487 >            Object k, v; Map.Entry<?,?> e;
1488 >            return ((o instanceof Map.Entry) &&
1489 >                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
1490 >                    (v = e.getValue()) != null &&
1491 >                    (k == key || k.equals(key)) &&
1492 >                    (v == val || v.equals(val)));
1493          }
1494  
1495          /**
# Line 1415 | Line 1501 | public class ConcurrentHashMapV8<K, V>
1501           * removed in which case the put will re-establish). We do not
1502           * and cannot guarantee more.
1503           */
1504 <        public V setValue(V value) {
1504 >        public final V setValue(V value) {
1505              if (value == null) throw new NullPointerException();
1506 <            V v = super.setValue(value);
1507 <            ConcurrentHashMapV8.this.put(getKey(), value);
1506 >            V v = val;
1507 >            val = value;
1508 >            map.put(key, value);
1509              return v;
1510          }
1511      }
1512  
1513 <    final class KeyIterator extends HashIterator
1427 <        implements Iterator<K>, Enumeration<K> {
1428 <        @SuppressWarnings("unchecked")
1429 <        public final K next()        { return (K)super.nextKey(); }
1430 <        @SuppressWarnings("unchecked")
1431 <        public final K nextElement() { return (K)super.nextKey(); }
1432 <    }
1513 >    /* ----------------Views -------------- */
1514  
1515 <    final class ValueIterator extends HashIterator
1516 <        implements Iterator<V>, Enumeration<V> {
1517 <        @SuppressWarnings("unchecked")
1518 <        public final V next()        { return (V)super.nextValue(); }
1438 <        @SuppressWarnings("unchecked")
1439 <        public final V nextElement() { return (V)super.nextValue(); }
1440 <    }
1515 >    /*
1516 >     * These currently just extend java.util.AbstractX classes, but
1517 >     * may need a new custom base to support partitioned traversal.
1518 >     */
1519  
1520 <    final class EntryIterator extends HashIterator
1521 <        implements Iterator<Entry<K,V>> {
1522 <        public final Map.Entry<K,V> next() { return super.nextEntry(); }
1445 <    }
1520 >    static final class KeySet<K,V> extends AbstractSet<K> {
1521 >        final ConcurrentHashMapV8<K, V> map;
1522 >        KeySet(ConcurrentHashMapV8<K, V> map)   { this.map = map; }
1523  
1524 <    final class KeySet extends AbstractSet<K> {
1525 <        public int size() {
1526 <            return ConcurrentHashMapV8.this.size();
1527 <        }
1528 <        public boolean isEmpty() {
1529 <            return ConcurrentHashMapV8.this.isEmpty();
1530 <        }
1454 <        public void clear() {
1455 <            ConcurrentHashMapV8.this.clear();
1456 <        }
1457 <        public Iterator<K> iterator() {
1458 <            return new KeyIterator();
1459 <        }
1460 <        public boolean contains(Object o) {
1461 <            return ConcurrentHashMapV8.this.containsKey(o);
1462 <        }
1463 <        public boolean remove(Object o) {
1464 <            return ConcurrentHashMapV8.this.remove(o) != null;
1524 >        public final int size()                 { return map.size(); }
1525 >        public final boolean isEmpty()          { return map.isEmpty(); }
1526 >        public final void clear()               { map.clear(); }
1527 >        public final boolean contains(Object o) { return map.containsKey(o); }
1528 >        public final boolean remove(Object o)   { return map.remove(o) != null; }
1529 >        public final Iterator<K> iterator() {
1530 >            return new KeyIterator<K,V>(map);
1531          }
1532      }
1533  
1534 <    final class Values extends AbstractCollection<V> {
1535 <        public int size() {
1536 <            return ConcurrentHashMapV8.this.size();
1537 <        }
1538 <        public boolean isEmpty() {
1539 <            return ConcurrentHashMapV8.this.isEmpty();
1540 <        }
1541 <        public void clear() {
1542 <            ConcurrentHashMapV8.this.clear();
1543 <        }
1478 <        public Iterator<V> iterator() {
1479 <            return new ValueIterator();
1480 <        }
1481 <        public boolean contains(Object o) {
1482 <            return ConcurrentHashMapV8.this.containsValue(o);
1534 >    static final class Values<K,V> extends AbstractCollection<V> {
1535 >        final ConcurrentHashMapV8<K, V> map;
1536 >        Values(ConcurrentHashMapV8<K, V> map)   { this.map = map; }
1537 >
1538 >        public final int size()                 { return map.size(); }
1539 >        public final boolean isEmpty()          { return map.isEmpty(); }
1540 >        public final void clear()               { map.clear(); }
1541 >        public final boolean contains(Object o) { return map.containsValue(o); }
1542 >        public final Iterator<V> iterator() {
1543 >            return new ValueIterator<K,V>(map);
1544          }
1545      }
1546  
1547 <    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1548 <        public int size() {
1549 <            return ConcurrentHashMapV8.this.size();
1550 <        }
1551 <        public boolean isEmpty() {
1552 <            return ConcurrentHashMapV8.this.isEmpty();
1553 <        }
1554 <        public void clear() {
1555 <            ConcurrentHashMapV8.this.clear();
1495 <        }
1496 <        public Iterator<Map.Entry<K,V>> iterator() {
1497 <            return new EntryIterator();
1547 >    static final class EntrySet<K,V> extends AbstractSet<Map.Entry<K,V>> {
1548 >        final ConcurrentHashMapV8<K, V> map;
1549 >        EntrySet(ConcurrentHashMapV8<K, V> map) { this.map = map; }
1550 >
1551 >        public final int size()                 { return map.size(); }
1552 >        public final boolean isEmpty()          { return map.isEmpty(); }
1553 >        public final void clear()               { map.clear(); }
1554 >        public final Iterator<Map.Entry<K,V>> iterator() {
1555 >            return new EntryIterator<K,V>(map);
1556          }
1557 <        public boolean contains(Object o) {
1558 <            if (!(o instanceof Map.Entry))
1559 <                return false;
1560 <            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1561 <            V v = ConcurrentHashMapV8.this.get(e.getKey());
1562 <            return v != null && v.equals(e.getValue());
1557 >
1558 >        public final boolean contains(Object o) {
1559 >            Object k, v, r; Map.Entry<?,?> e;
1560 >            return ((o instanceof Map.Entry) &&
1561 >                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
1562 >                    (r = map.get(k)) != null &&
1563 >                    (v = e.getValue()) != null &&
1564 >                    (v == r || v.equals(r)));
1565          }
1566 <        public boolean remove(Object o) {
1567 <            if (!(o instanceof Map.Entry))
1568 <                return false;
1569 <            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1570 <            return ConcurrentHashMapV8.this.remove(e.getKey(), e.getValue());
1566 >
1567 >        public final boolean remove(Object o) {
1568 >            Object k, v; Map.Entry<?,?> e;
1569 >            return ((o instanceof Map.Entry) &&
1570 >                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
1571 >                    (v = e.getValue()) != null &&
1572 >                    map.remove(k, v));
1573          }
1574      }
1575  
1576      /* ---------------- Serialization Support -------------- */
1577  
1578      /**
1579 <     * Helper class used in previous version, declared for the sake of
1580 <     * serialization compatibility
1579 >     * Stripped-down version of helper class used in previous version,
1580 >     * declared for the sake of serialization compatibility
1581       */
1582 <    static class Segment<K,V> extends java.util.concurrent.locks.ReentrantLock
1521 <        implements Serializable {
1582 >    static class Segment<K,V> implements Serializable {
1583          private static final long serialVersionUID = 2249069246763182397L;
1584          final float loadFactor;
1585          Segment(float lf) { this.loadFactor = lf; }
# Line 1540 | Line 1601 | public class ConcurrentHashMapV8<K, V>
1601              segments = (Segment<K,V>[])
1602                  new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
1603              for (int i = 0; i < segments.length; ++i)
1604 <                segments[i] = new Segment<K,V>(loadFactor);
1604 >                segments[i] = new Segment<K,V>(LOAD_FACTOR);
1605          }
1606          s.defaultWriteObject();
1607 <        new HashIterator().writeEntries(s);
1607 >        InternalIterator it = new InternalIterator(table);
1608 >        while (it.next != null) {
1609 >            s.writeObject(it.nextKey);
1610 >            s.writeObject(it.nextVal);
1611 >            it.advance();
1612 >        }
1613          s.writeObject(null);
1614          s.writeObject(null);
1615          segments = null; // throw away
1616      }
1617  
1618      /**
1619 <     * Reconstitutes the  instance from a
1554 <     * stream (i.e., deserializes it).
1619 >     * Reconstitutes the instance from a stream (that is, deserializes it).
1620       * @param s the stream
1621       */
1622      @SuppressWarnings("unchecked")
1623      private void readObject(java.io.ObjectInputStream s)
1624              throws java.io.IOException, ClassNotFoundException {
1625          s.defaultReadObject();
1561        // find load factor in a segment, if one exists
1562        if (segments != null && segments.length != 0)
1563            this.loadFactor = segments[0].loadFactor;
1564        else
1565            this.loadFactor = DEFAULT_LOAD_FACTOR;
1566        this.initCap = DEFAULT_CAPACITY;
1567        LongAdder ct = new LongAdder(); // force final field write
1568        UNSAFE.putObjectVolatile(this, counterOffset, ct);
1626          this.segments = null; // unneeded
1627 <
1628 <        // Read the keys and values, and put the mappings in the table
1627 >        // initialize transient final field
1628 >        UNSAFE.putObjectVolatile(this, counterOffset, new LongAdder());
1629 >        this.targetCapacity = DEFAULT_CAPACITY;
1630 >
1631 >        // Create all nodes, then place in table once size is known
1632 >        long size = 0L;
1633 >        Node p = null;
1634          for (;;) {
1635 <            K key = (K) s.readObject();
1636 <            V value = (V) s.readObject();
1637 <            if (key == null)
1635 >            K k = (K) s.readObject();
1636 >            V v = (V) s.readObject();
1637 >            if (k != null && v != null) {
1638 >                p = new Node(spread(k.hashCode()), k, v, p);
1639 >                ++size;
1640 >            }
1641 >            else
1642                  break;
1643 <            put(key, value);
1643 >        }
1644 >        if (p != null) {
1645 >            boolean init = false;
1646 >            if (resizing == 0 &&
1647 >                UNSAFE.compareAndSwapInt(this, resizingOffset, 0, 1)) {
1648 >                try {
1649 >                    if (table == null) {
1650 >                        init = true;
1651 >                        int n;
1652 >                        if (size >= (long)(MAXIMUM_CAPACITY >>> 1))
1653 >                            n = MAXIMUM_CAPACITY;
1654 >                        else {
1655 >                            int sz = (int)size;
1656 >                            n = tableSizeFor(sz + (sz >>> 1) + 1);
1657 >                        }
1658 >                        threshold = n - (n >>> 2) - THRESHOLD_OFFSET;
1659 >                        Node[] tab = new Node[n];
1660 >                        int mask = n - 1;
1661 >                        while (p != null) {
1662 >                            int j = p.hash & mask;
1663 >                            Node next = p.next;
1664 >                            p.next = tabAt(tab, j);
1665 >                            setTabAt(tab, j, p);
1666 >                            p = next;
1667 >                        }
1668 >                        table = tab;
1669 >                        counter.add(size);
1670 >                    }
1671 >                } finally {
1672 >                    resizing = 0;
1673 >                }
1674 >            }
1675 >            if (!init) { // Can only happen if unsafely published.
1676 >                while (p != null) {
1677 >                    internalPut(p.key, p.val, true);
1678 >                    p = p.next;
1679 >                }
1680 >            }
1681          }
1682      }
1683  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines