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.14 by dl, Tue Sep 6 00:26:27 2011 UTC vs.
Revision 1.25 by dl, Mon Sep 19 12:31:07 2011 UTC

# Line 6 | Line 6
6  
7   package jsr166e;
8   import jsr166e.LongAdder;
9 + import java.util.Arrays;
10   import java.util.Map;
11   import java.util.Set;
12   import java.util.Collection;
# Line 19 | Line 20 | import java.util.Enumeration;
20   import java.util.ConcurrentModificationException;
21   import java.util.NoSuchElementException;
22   import java.util.concurrent.ConcurrentMap;
23 + import java.util.concurrent.locks.LockSupport;
24   import java.io.Serializable;
25  
26   /**
# Line 49 | Line 51 | import java.io.Serializable;
51   * are typically useful only when a map is not undergoing concurrent
52   * updates in other threads.  Otherwise the results of these methods
53   * reflect transient states that may be adequate for monitoring
54 < * purposes, but not for program control.
54 > * or estimation purposes, but not for program control.
55   *
56 < * <p> Resizing this or any other kind of hash table is a relatively
57 < * slow operation, so, when possible, it is a good idea to provide
58 < * estimates of expected table sizes in constructors. Also, for
59 < * compatibility with previous versions of this class, constructors
60 < * may optionally specify an expected {@code concurrencyLevel} as an
61 < * additional hint for internal sizing.
56 > * <p> The table is dynamically expanded when there are too many
57 > * collisions (i.e., keys that have distinct hash codes but fall into
58 > * the same slot modulo the table size), with the expected average
59 > * effect of maintaining roughly two bins per mapping (corresponding
60 > * to a 0.75 load factor threshold for resizing). There may be much
61 > * variance around this average as mappings are added and removed, but
62 > * overall, this maintains a commonly accepted time/space tradeoff for
63 > * hash tables.  However, resizing this or any other kind of hash
64 > * table may be a relatively slow operation. When possible, it is a
65 > * good idea to provide a size estimate as an optional {@code
66 > * initialCapacity} constructor argument. An additional optional
67 > * {@code loadFactor} constructor argument provides a further means of
68 > * customizing initial table capacity by specifying the table density
69 > * to be used in calculating the amount of space to allocate for the
70 > * given number of elements.  Also, for compatibility with previous
71 > * versions of this class, constructors may optionally specify an
72 > * expected {@code concurrencyLevel} as an additional hint for
73 > * internal sizing.  Note that using many keys with exactly the same
74 > * {@code hashCode{}} is a sure way to slow down performance of any
75 > * hash table.
76   *
77   * <p>This class and its views and iterators implement all of the
78   * <em>optional</em> methods of the {@link Map} and {@link Iterator}
# Line 108 | Line 124 | public class ConcurrentHashMapV8<K, V>
124       * The primary design goal of this hash table is to maintain
125       * concurrent readability (typically method get(), but also
126       * iterators and related methods) while minimizing update
127 <     * contention.
127 >     * contention. Secondary goals are to keep space consumption about
128 >     * the same or better than java.util.HashMap, and to support high
129 >     * initial insertion rates on an empty table by many threads.
130       *
131       * Each key-value mapping is held in a Node.  Because Node fields
132       * can contain special values, they are defined using plain Object
# Line 126 | Line 144 | public class ConcurrentHashMapV8<K, V>
144       * we use intrinsics (sun.misc.Unsafe) operations.  The lists of
145       * nodes within bins are always accurately traversable under
146       * volatile reads, so long as lookups check hash code and
147 <     * non-nullness of value before checking key equality. (All valid
148 <     * hash codes are nonnegative. Negative values are reserved for
149 <     * special forwarding nodes; see below.)
147 >     * non-nullness of value before checking key equality.
148 >     *
149 >     * We use the top two bits of Node hash fields for control
150 >     * purposes -- they are available anyway because of addressing
151 >     * constraints.  As explained further below, these top bits are
152 >     * usd as follows:
153 >     *  00 - Normal
154 >     *  01 - Locked
155 >     *  11 - Locked and may have a thread waiting for lock
156 >     *  10 - Node is a forwarding node
157 >     *
158 >     * The lower 30 bits of each Node's hash field contain a
159 >     * transformation (for better randomization -- method "spread") of
160 >     * the key's hash code, except for forwarding nodes, for which the
161 >     * lower bits are zero (and so always have hash field == "MOVED").
162       *
163       * Insertion (via put or putIfAbsent) of the first node in an
164       * empty bin is performed by just CASing it to the bin.  This is
165 <     * on average by far the most common case for put operations.
166 <     * Other update operations (insert, delete, and replace) require
167 <     * locks.  We do not want to waste the space required to associate
168 <     * a distinct lock object with each bin, so instead use the first
169 <     * node of a bin list itself as a lock, using plain "synchronized"
170 <     * locks. These save space and we can live with block-structured
171 <     * lock/unlock operations. Using the first node of a list as a
172 <     * lock does not by itself suffice though: When a node is locked,
173 <     * any update must first validate that it is still the first node,
174 <     * and retry if not. Because new nodes are always appended to
175 <     * lists, once a node is first in a bin, it remains first until
176 <     * deleted or the bin becomes invalidated.  However, operations
177 <     * that only conditionally update can and sometimes do inspect
178 <     * nodes until the point of update. This is a converse of sorts to
179 <     * the lazy locking technique described by Herlihy & Shavit.
165 >     * by far the most common case for put operations.  Other update
166 >     * operations (insert, delete, and replace) require locks.  We do
167 >     * not want to waste the space required to associate a distinct
168 >     * lock object with each bin, so instead use the first node of a
169 >     * bin list itself as a lock. Blocking support for these locks
170 >     * relies on the builtin "synchronized" monitors.  However, we
171 >     * also need a tryLock construction, so we overlay these by using
172 >     * bits of the Node hash field for lock control (see above), and
173 >     * so normally use builtin monitors only for blocking and
174 >     * signalling using wait/notifyAll constructions. See
175 >     * Node.tryAwaitLock.
176 >     *
177 >     * Using the first node of a list as a lock does not by itself
178 >     * suffice though: When a node is locked, any update must first
179 >     * validate that it is still the first node after locking it, and
180 >     * retry if not. Because new nodes are always appended to lists,
181 >     * once a node is first in a bin, it remains first until deleted
182 >     * or the bin becomes invalidated.  However, operations that only
183 >     * conditionally update may inspect nodes until the point of
184 >     * update. This is a converse of sorts to the lazy locking
185 >     * technique described by Herlihy & Shavit.
186       *
187 <     * The main disadvantage of this approach is that most update
187 >     * The main disadvantage of per-bin locks is that other update
188       * operations on other nodes in a bin list protected by the same
189       * lock can stall, for example when user equals() or mapping
190       * functions take a long time.  However, statistically, this is
# Line 156 | Line 192 | public class ConcurrentHashMapV8<K, V>
192       * of alternatives: Under random hash codes, the frequency of
193       * nodes in bins follows a Poisson distribution
194       * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
195 <     * parameter of 0.5 on average under the default loadFactor of
196 <     * 0.75. The expected number of locks covering different elements
197 <     * (i.e., bins with 2 or more nodes) is approximately 10% at
198 <     * steady state.  Lock contention probability for two threads
199 <     * accessing distinct elements is roughly 1 / (8 * #elements).
200 <     * Function "spread" performs hashCode randomization that improves
201 <     * the likelihood that these assumptions hold unless users define
202 <     * exactly the same value for too many hashCodes.
203 <     *
204 <     * The table is resized when occupancy exceeds a threshold.  Only
205 <     * a single thread performs the resize (using field "resizing", to
206 <     * arrange exclusion), but the table otherwise remains usable for
207 <     * reads and updates. Resizing proceeds by transferring bins, one
208 <     * by one, from the table to the next table.  Upon transfer, the
209 <     * old table bin contains only a special forwarding node (with
210 <     * negative hash field) that contains the next table as its
211 <     * key. On encountering a forwarding node, access and update
212 <     * operations restart, using the new table. To ensure concurrent
213 <     * readability of traversals, transfers must proceed from the last
214 <     * bin (table.length - 1) up towards the first.  Upon seeing a
215 <     * forwarding node, traversals (see class InternalIterator)
216 <     * arrange to move to the new table for the rest of the traversal
217 <     * without revisiting nodes.  This constrains bin transfers to a
218 <     * particular order, and so can block indefinitely waiting for the
219 <     * next lock, and other threads cannot help with the transfer.
220 <     * However, expected stalls are infrequent enough to not warrant
221 <     * the additional overhead of access and iteration schemes that
222 <     * could admit out-of-order or concurrent bin transfers.
195 >     * parameter of about 0.5 on average, given the resizing threshold
196 >     * of 0.75, although with a large variance because of resizing
197 >     * granularity. Ignoring variance, the expected occurrences of
198 >     * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The
199 >     * first few values are:
200 >     *
201 >     * 0:    0.607
202 >     * 1:    0.303
203 >     * 2:    0.076
204 >     * 3:    0.012
205 >     * more: 0.002
206 >     *
207 >     * Lock contention probability for two threads accessing distinct
208 >     * elements is roughly 1 / (8 * #elements).  Function "spread"
209 >     * performs hashCode randomization that improves the likelihood
210 >     * that these assumptions hold unless users define exactly the
211 >     * same value for too many hashCodes.
212 >     *
213 >     * The table is resized when occupancy exceeds an occupancy
214 >     * threshold (nominally, 0.75, but see below).  Only a single
215 >     * thread performs the resize (using field "sizeCtl", to arrange
216 >     * exclusion), but the table otherwise remains usable for reads
217 >     * and updates. Resizing proceeds by transferring bins, one by
218 >     * one, from the table to the next table.  Because we are using
219 >     * power-of-two expansion, the elements from each bin must either
220 >     * stay at same index, or move with a power of two offset. We
221 >     * eliminate unnecessary node creation by catching cases where old
222 >     * nodes can be reused because their next fields won't change.  On
223 >     * average, only about one-sixth of them need cloning when a table
224 >     * doubles. The nodes they replace will be garbage collectable as
225 >     * soon as they are no longer referenced by any reader thread that
226 >     * may be in the midst of concurrently traversing table.  Upon
227 >     * transfer, the old table bin contains only a special forwarding
228 >     * node (with hash field "MOVED") that contains the next table as
229 >     * its key. On encountering a forwarding node, access and update
230 >     * operations restart, using the new table.
231 >     *
232 >     * Each bin transfer requires its bin lock. However, unlike other
233 >     * cases, a transfer can skip a bin if it fails to acquire its
234 >     * lock, and revisit it later. Method rebuild maintains a buffer
235 >     * of TRANSFER_BUFFER_SIZE bins that have been skipped because of
236 >     * failure to acquire a lock, and blocks only if none are
237 >     * available (i.e., only very rarely).  The transfer operation
238 >     * must also ensure that all accessible bins in both the old and
239 >     * new table are usable by any traversal.  When there are no lock
240 >     * acquisition failures, this is arranged simply by proceeding
241 >     * from the last bin (table.length - 1) up towards the first.
242 >     * Upon seeing a forwarding node, traversals (see class
243 >     * InternalIterator) arrange to move to the new table without
244 >     * revisiting nodes.  However, when any node is skipped during a
245 >     * transfer, all earlier table bins may have become visible, so
246 >     * are initialized with a reverse-forwarding node back to the old
247 >     * table until the new ones are established. (This sometimes
248 >     * requires transiently locking a forwarding node, which is
249 >     * possible under the above encoding.) These more expensive
250 >     * mechanics trigger only when necessary.
251       *
252 <     * This traversal scheme also applies to partial traversals of
252 >     * The traversal scheme also applies to partial traversals of
253       * ranges of bins (via an alternate InternalIterator constructor)
254       * to support partitioned aggregate operations (that are not
255       * otherwise implemented yet).  Also, read-only operations give up
# Line 196 | Line 260 | public class ConcurrentHashMapV8<K, V>
260       * Lazy table initialization minimizes footprint until first use,
261       * and also avoids resizings when the first operation is from a
262       * putAll, constructor with map argument, or deserialization.
263 <     * These cases attempt to override the targetCapacity used in
264 <     * growTable (which may harmlessly fail to take effect in cases of
201 <     * races with other ongoing resizings).
263 >     * These cases attempt to override the initial capacity settings,
264 >     * but harmlessly fail to take effect in cases of races.
265       *
266       * The element count is maintained using a LongAdder, which avoids
267       * contention on updates but can encounter cache thrashing if read
268       * too frequently during concurrent access. To avoid reading so
269       * often, resizing is normally attempted only upon adding to a bin
270 <     * already holding two or more nodes. Under the default load
271 <     * factor and uniform hash distributions, the probability of this
272 <     * occurring at threshold is around 13%, meaning that only about 1
273 <     * in 8 puts check threshold (and after resizing, many fewer do
274 <     * so). But this approximation has high variance for small table
275 <     * sizes, so we check on any collision for sizes <= 64.  Further,
213 <     * to increase the probability that a resize occurs soon enough,
214 <     * we offset the threshold (see THRESHOLD_OFFSET) by the expected
215 <     * number of puts between checks. This is currently set to 8, in
216 <     * accord with the default load factor. In practice, this default
217 <     * is rarely overridden, and in any case is close enough to other
218 <     * plausible values not to waste dynamic probability computation
219 <     * for the sake of more precision.
270 >     * already holding two or more nodes. Under uniform hash
271 >     * distributions, the probability of this occurring at threshold
272 >     * is around 13%, meaning that only about 1 in 8 puts check
273 >     * threshold (and after resizing, many fewer do so). But this
274 >     * approximation has high variance for small table sizes, so we
275 >     * check on any collision for sizes <= 64.
276       *
277       * Maintaining API and serialization compatibility with previous
278       * versions of this class introduces several oddities. Mainly: We
279       * leave untouched but unused constructor arguments refering to
280 <     * concurrencyLevel. We also declare an unused "Segment" class
281 <     * that is instantiated in minimal form only when serializing.
280 >     * concurrencyLevel. We accept a loadFactor constructor argument,
281 >     * but apply it only to initial table capacity (which is the only
282 >     * time that we can guarantee to honor it.) We also declare an
283 >     * unused "Segment" class that is instantiated in minimal form
284 >     * only when serializing.
285       */
286  
287      /* ---------------- Constants -------------- */
288  
289      /**
290 <     * The largest allowed table capacity.  Must be a power of 2, at
291 <     * most 1<<30 to stay within Java array size limits.
290 >     * The largest possible table capacity.  This value must be
291 >     * exactly 1<<30 to stay within Java array allocation and indexing
292 >     * bounds for power of two table sizes, and is further required
293 >     * because the top two bits of 32bit hash fields are used for
294 >     * control purposes.
295       */
296      private static final int MAXIMUM_CAPACITY = 1 << 30;
297  
# Line 240 | Line 302 | public class ConcurrentHashMapV8<K, V>
302      private static final int DEFAULT_CAPACITY = 16;
303  
304      /**
305 <     * The default load factor for this table, used when not otherwise
306 <     * specified in a constructor.
305 >     * The largest possible (non-power of two) array size.
306 >     * Needed by toArray and related methods.
307       */
308 <    private static final float DEFAULT_LOAD_FACTOR = 0.75f;
308 >    static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
309  
310      /**
311 <     * The default concurrency level for this table. Unused, but
311 >     * The default concurrency level for this table. Unused but
312       * defined for compatibility with previous versions of this class.
313       */
314      private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
315  
316      /**
317 <     * The count value to offset thresholds to compensate for checking
318 <     * for the need to resize only when inserting into bins with two
319 <     * or more elements. See above for explanation.
317 >     * The load factor for this table. Overrides of this value in
318 >     * constructors affect only the initial table capacity.  The
319 >     * actual floating point value isn't normally used -- it is
320 >     * simpler to use expressions such as {@code n - (n >>> 2)} for
321 >     * the associated resizing threshold.
322       */
323 <    private static final int THRESHOLD_OFFSET = 8;
260 <
261 <    /* ---------------- Nodes -------------- */
323 >    private static final float LOAD_FACTOR = 0.75f;
324  
325      /**
326 <     * Key-value entry. Note that this is never exported out as a
327 <     * user-visible Map.Entry. Nodes with a negative hash field are
328 <     * special, and do not contain user keys or values.  Otherwise,
267 <     * keys are never null, and null val fields indicate that a node
268 <     * is in the process of being deleted or created. For purposes of
269 <     * read-only, access, a key may be read before a val, but can only
270 <     * be used after checking val.  (For an update operation, when a
271 <     * lock is held on a node, order doesn't matter.)
326 >     * The buffer size for skipped bins during transfers. The
327 >     * value is arbitrary but should be large enough to avoid
328 >     * most locking stalls during resizes.
329       */
330 <    static final class Node {
274 <        final int hash;
275 <        final Object key;
276 <        volatile Object val;
277 <        volatile Node next;
278 <
279 <        Node(int hash, Object key, Object val, Node next) {
280 <            this.hash = hash;
281 <            this.key = key;
282 <            this.val = val;
283 <            this.next = next;
284 <        }
285 <    }
330 >    private static final int TRANSFER_BUFFER_SIZE = 32;
331  
332 <    /**
333 <     * Sign bit of node hash value indicating to use table in node.key.
332 >    /*
333 >     * Encodings for special uses of Node hash fields. See above for
334 >     * explanation.
335       */
336 <    private static final int SIGN_BIT = 0x80000000;
336 >    static final int MOVED     = 0x80000000; // hash field for fowarding nodes
337 >    static final int LOCKED    = 0x40000000; // set/tested only as a bit
338 >    static final int WAITING   = 0xc0000000; // both bits set/tested together
339 >    static final int HASH_BITS = 0x3fffffff; // usable bits of normal node hash
340  
341      /* ---------------- Fields -------------- */
342  
# Line 297 | Line 346 | public class ConcurrentHashMapV8<K, V>
346       */
347      transient volatile Node[] table;
348  
349 <    /** The counter maintaining number of elements. */
349 >    /**
350 >     * The counter maintaining number of elements.
351 >     */
352      private transient final LongAdder counter;
353 <    /** Nonzero when table is being initialized or resized. Updated via CAS. */
354 <    private transient volatile int resizing;
355 <    /** The next element count value upon which to resize the table. */
356 <    private transient int threshold;
357 <    /** The target capacity; volatile to cover initialization races. */
358 <    private transient volatile int targetCapacity;
359 <    /** The target load factor for the table */
360 <    private transient final float loadFactor;
353 >
354 >    /**
355 >     * Table initialization and resizing control.  When negative, the
356 >     * table is being initialized or resized. Otherwise, when table is
357 >     * null, holds the initial table size to use upon creation, or 0
358 >     * for default. After initialization, holds the next element count
359 >     * value upon which to resize the table.
360 >     */
361 >    private transient volatile int sizeCtl;
362  
363      // views
364      private transient KeySet<K,V> keySet;
# Line 316 | Line 368 | public class ConcurrentHashMapV8<K, V>
368      /** For serialization compatibility. Null unless serialized; see below */
369      private Segment<K,V>[] segments;
370  
371 +    /* ---------------- Nodes -------------- */
372 +
373 +    /**
374 +     * Key-value entry. Note that this is never exported out as a
375 +     * user-visible Map.Entry (see WriteThroughEntry and SnapshotEntry
376 +     * below). Nodes with a negative hash field are special, and do
377 +     * not contain user keys or values.  Otherwise, keys are never
378 +     * null, and null val fields indicate that a node is in the
379 +     * process of being deleted or created. For purposes of read-only
380 +     * access, a key may be read before a val, but can only be used
381 +     * after checking val to be non-null.
382 +     */
383 +    static final class Node {
384 +        volatile int hash;
385 +        final Object key;
386 +        volatile Object val;
387 +        volatile Node next;
388 +
389 +        Node(int hash, Object key, Object val, Node next) {
390 +            this.hash = hash;
391 +            this.key = key;
392 +            this.val = val;
393 +            this.next = next;
394 +        }
395 +
396 +        /** CompareAndSet the hash field */
397 +        final boolean casHash(int cmp, int val) {
398 +            return UNSAFE.compareAndSwapInt(this, hashOffset, cmp, val);
399 +        }
400 +
401 +        /** The number of spins before blocking for a lock */
402 +        static final int MAX_SPINS =
403 +            Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
404 +
405 +        /**
406 +         * Spins a while if LOCKED bit set and this node is the first
407 +         * of its bin, and then sets WAITING bits on hash field and
408 +         * blocks (once) if they are still set.  It is OK for this
409 +         * method to return even if lock is not available upon exit,
410 +         * which enables these simple single-wait mechanics.
411 +         *
412 +         * The corresponding signalling operation is performed within
413 +         * callers: Upon detecting that WAITING has been set when
414 +         * unlocking lock (via a failed CAS from non-waiting LOCKED
415 +         * state), unlockers acquire the sync lock and perform a
416 +         * notifyAll.
417 +         */
418 +        final void tryAwaitLock(Node[] tab, int i) {
419 +            if (tab != null && i >= 0 && i < tab.length) { // bounds check
420 +                int spins = MAX_SPINS, h;
421 +                while (tabAt(tab, i) == this && ((h = hash) & LOCKED) != 0) {
422 +                    if (spins >= 0) {
423 +                        if (--spins == MAX_SPINS >>> 1)
424 +                            Thread.yield();  // heuristically yield mid-way
425 +                    }
426 +                    else if (casHash(h, h | WAITING)) {
427 +                        synchronized(this) {
428 +                            if (tabAt(tab, i) == this &&
429 +                                (hash & WAITING) == WAITING) {
430 +                                try {
431 +                                    wait();
432 +                                } catch (InterruptedException ie) {
433 +                                    Thread.currentThread().interrupt();
434 +                                }
435 +                            }
436 +                            else
437 +                                notifyAll(); // possibly won race vs signaller
438 +                        }
439 +                        break;
440 +                    }
441 +                }
442 +            }
443 +        }
444 +
445 +        // Unsafe mechanics for casHash
446 +        private static final sun.misc.Unsafe UNSAFE;
447 +        private static final long hashOffset;
448 +
449 +        static {
450 +            try {
451 +                UNSAFE = getUnsafe();
452 +                Class<?> k = Node.class;
453 +                hashOffset = UNSAFE.objectFieldOffset
454 +                    (k.getDeclaredField("hash"));
455 +            } catch (Exception e) {
456 +                throw new Error(e);
457 +            }
458 +        }
459 +    }
460 +
461      /* ---------------- Table element access -------------- */
462  
463      /*
# Line 342 | Line 484 | public class ConcurrentHashMapV8<K, V>
484          UNSAFE.putObjectVolatile(tab, ((long)i<<ASHIFT)+ABASE, v);
485      }
486  
345    /* ----------------Table Initialization and Resizing -------------- */
346
347    /**
348     * Returns a power of two table size for the given desired capacity.
349     * See Hackers Delight, sec 3.2
350     */
351    private static final int tableSizeFor(int c) {
352        int n = c - 1;
353        n |= n >>> 1;
354        n |= n >>> 2;
355        n |= n >>> 4;
356        n |= n >>> 8;
357        n |= n >>> 16;
358        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
359    }
360
361    /**
362     * If not already resizing, initializes or creates next table and
363     * transfers bins. Initial table size uses the capacity recorded
364     * in targetCapacity.  Rechecks occupancy after a transfer to see
365     * if another resize is already needed because resizings are
366     * lagging additions.
367     *
368     * @return current table
369     */
370    private final Node[] growTable() {
371        if (resizing == 0 &&
372            UNSAFE.compareAndSwapInt(this, resizingOffset, 0, 1)) {
373            try {
374                for (;;) {
375                    Node[] tab = table;
376                    int n, c;
377                    if (tab == null)
378                        n = (c = targetCapacity) > 0 ? c : DEFAULT_CAPACITY;
379                    else if ((n = tab.length) < MAXIMUM_CAPACITY &&
380                             counter.sum() >= threshold)
381                        n <<= 1;
382                    else
383                        break;
384                    Node[] nextTab = new Node[n];
385                    threshold = (int)(n * loadFactor) - THRESHOLD_OFFSET;
386                    if (tab != null)
387                        transfer(tab, nextTab,
388                                 new Node(SIGN_BIT, nextTab, null, null));
389                    table = nextTab;
390                    if (tab == null)
391                        break;
392                }
393            } finally {
394                resizing = 0;
395            }
396        }
397        else if (table == null)
398            Thread.yield(); // lost initialization race; just spin
399        return table;
400    }
401
402    /*
403     * Reclassifies nodes in each bin to new table.  Because we are
404     * using power-of-two expansion, the elements from each bin must
405     * either stay at same index, or move with a power of two
406     * offset. We eliminate unnecessary node creation by catching
407     * cases where old nodes can be reused because their next fields
408     * won't change.  Statistically, at the default loadFactor, only
409     * about one-sixth of them need cloning when a table doubles. The
410     * nodes they replace will be garbage collectable as soon as they
411     * are no longer referenced by any reader thread that may be in
412     * the midst of concurrently traversing table.
413     *
414     * Transfers are done from the bottom up to preserve iterator
415     * traversability. On each step, the old bin is locked,
416     * moved/copied, and then replaced with a forwarding node.
417     */
418    private static final void transfer(Node[] tab, Node[] nextTab, Node fwd) {
419        int n = tab.length;
420        Node ignore = nextTab[n + n - 1]; // force bounds check
421        for (int i = n - 1; i >= 0; --i) {
422            for (Node e;;) {
423                if ((e = tabAt(tab, i)) != null) {
424                    boolean validated = false;
425                    synchronized (e) {
426                        if (tabAt(tab, i) == e) {
427                            validated = true;
428                            Node lo = null, hi = null, lastRun = e;
429                            int runBit = e.hash & n;
430                            for (Node p = e.next; p != null; p = p.next) {
431                                int b = p.hash & n;
432                                if (b != runBit) {
433                                    runBit = b;
434                                    lastRun = p;
435                                }
436                            }
437                            if (runBit == 0)
438                                lo = lastRun;
439                            else
440                                hi = lastRun;
441                            for (Node p = e; p != lastRun; p = p.next) {
442                                int ph = p.hash;
443                                Object pk = p.key, pv = p.val;
444                                if ((ph & n) == 0)
445                                    lo = new Node(ph, pk, pv, lo);
446                                else
447                                    hi = new Node(ph, pk, pv, hi);
448                            }
449                            setTabAt(nextTab, i, lo);
450                            setTabAt(nextTab, i + n, hi);
451                            setTabAt(tab, i, fwd);
452                        }
453                    }
454                    if (validated)
455                        break;
456                }
457                else if (casTabAt(tab, i, e, fwd))
458                    break;
459            }
460        }
461    }
462
487      /* ---------------- Internal access and update methods -------------- */
488  
489      /**
490       * Applies a supplemental hash function to a given hashCode, which
491       * defends against poor quality hash functions.  The result must
492 <     * be non-negative, and for reasonable performance must have good
493 <     * avalanche properties; i.e., that each bit of the argument
494 <     * affects each bit (except sign bit) of the result.
492 >     * be have the top 2 bits clear. For reasonable performance, this
493 >     * function must have good avalanche properties; i.e., that each
494 >     * bit of the argument affects each bit of the result. (Although
495 >     * we don't care about the unused top 2 bits.)
496       */
497      private static final int spread(int h) {
498          // Apply base step of MurmurHash; see http://code.google.com/p/smhasher/
# Line 475 | Line 500 | public class ConcurrentHashMapV8<K, V>
500          h *= 0x85ebca6b;
501          h ^= h >>> 13;
502          h *= 0xc2b2ae35;
503 <        return (h >>> 16) ^ (h & 0x7fffffff); // mask out sign bit
503 >        return ((h >>> 16) ^ h) & HASH_BITS; // mask out top bits
504      }
505  
506      /** Implementation for get and containsKey */
507      private final Object internalGet(Object k) {
508          int h = spread(k.hashCode());
509          retry: for (Node[] tab = table; tab != null;) {
510 <            Node e; Object ek, ev; int eh;  // locals to read fields once
510 >            Node e; Object ek, ev; int eh;    // locals to read fields once
511              for (e = tabAt(tab, (tab.length - 1) & h); e != null; e = e.next) {
512 <                if ((eh = e.hash) == h) {
513 <                    if ((ev = e.val) != null &&
489 <                        ((ek = e.key) == k || k.equals(ek)))
490 <                        return ev;
491 <                }
492 <                else if (eh < 0) {          // sign bit set
493 <                    tab = (Node[])e.key;    // bin was moved during resize
512 >                if ((eh = e.hash) == MOVED) {
513 >                    tab = (Node[])e.key;      // restart with new table
514                      continue retry;
515                  }
516 +                if ((eh & HASH_BITS) == h && (ev = e.val) != null &&
517 +                    ((ek = e.key) == k || k.equals(ek)))
518 +                    return ev;
519              }
520              break;
521          }
# Line 504 | Line 527 | public class ConcurrentHashMapV8<K, V>
527          int h = spread(k.hashCode());
528          Object oldVal = null;               // previous value or null if none
529          for (Node[] tab = table;;) {
530 <            Node e; int i; Object ek, ev;
530 >            int i; Node f; int fh; Object fk, fv;
531              if (tab == null)
532 <                tab = growTable();
533 <            else if ((e = tabAt(tab, i = (tab.length - 1) & h)) == null) {
532 >                tab = initTable();
533 >            else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) {
534                  if (casTabAt(tab, i, null, new Node(h, k, v, null)))
535                      break;                   // no lock when adding to empty bin
536              }
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
520 <                    break;
521 <                }
537 >            else if ((fh = f.hash) == MOVED)
538 >                tab = (Node[])f.key;
539 >            else if (!replace && (fh & HASH_BITS) == h && (fv = f.val) != null &&
540 >                     ((fk = f.key) == k || k.equals(fk))) {
541 >                oldVal = fv;                // precheck 1st node for putIfAbsent
542 >                break;
543              }
544 <            else {
544 >            else if ((fh & LOCKED) != 0)
545 >                f.tryAwaitLock(tab, i);
546 >            else if (f.casHash(fh, fh | LOCKED)) {
547                  boolean validated = false;
548                  boolean checkSize = false;
549 <                synchronized (e) {           // lock the 1st node of bin list
550 <                    if (tabAt(tab, i) == e) {
549 >                try {
550 >                    if (tabAt(tab, i) == f) {
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) {
552 >                        for (Node e = f;;) {
553 >                            Object ek, ev;
554 >                            if ((e.hash & HASH_BITS) == h &&
555 >                                (ev = e.val) != null &&
556 >                                ((ek = e.key) == k || k.equals(ek))) {
557                                  oldVal = ev;
558                                  if (replace)
559                                      e.val = v;
# Line 538 | Line 562 | public class ConcurrentHashMapV8<K, V>
562                              Node last = e;
563                              if ((e = e.next) == null) {
564                                  last.next = new Node(h, k, v, null);
565 <                                if (last != first || tab.length <= 64)
565 >                                if (last != f || tab.length <= 64)
566                                      checkSize = true;
567                                  break;
568                              }
569                          }
570                      }
571 +                } finally {                  // unlock and signal if needed
572 +                    if (!f.casHash(fh | LOCKED, fh)) {
573 +                        f.hash = fh;
574 +                        synchronized(f) { f.notifyAll(); };
575 +                    }
576                  }
577                  if (validated) {
578 +                    int sc;
579                      if (checkSize && tab.length < MAXIMUM_CAPACITY &&
580 <                        resizing == 0 && counter.sum() >= threshold)
580 >                        (sc = sizeCtl) >= 0 && counter.sum() >= (long)sc)
581                          growTable();
582                      break;
583                  }
# Line 565 | Line 595 | public class ConcurrentHashMapV8<K, V>
595       */
596      private final Object internalReplace(Object k, Object v, Object cv) {
597          int h = spread(k.hashCode());
598 +        Object oldVal = null;
599          for (Node[] tab = table;;) {
600 <            Node e; int i;
600 >            Node f; int i, fh;
601              if (tab == null ||
602 <                (e = tabAt(tab, i = (tab.length - 1) & h)) == null)
603 <                return null;
604 <            else if (e.hash < 0)
605 <                tab = (Node[])e.key;
606 <            else {
607 <                Object oldVal = null;
602 >                (f = tabAt(tab, i = (tab.length - 1) & h)) == null)
603 >                break;
604 >            else if ((fh = f.hash) == MOVED)
605 >                tab = (Node[])f.key;
606 >            else if ((fh & HASH_BITS) != h && f.next == null) // precheck
607 >                break;                          // rules out possible existence
608 >            else if ((fh & LOCKED) != 0)
609 >                f.tryAwaitLock(tab, i);
610 >            else if (f.casHash(fh, fh | LOCKED)) {
611                  boolean validated = false;
612                  boolean deleted = false;
613 <                synchronized (e) {
614 <                    if (tabAt(tab, i) == e) {
613 >                try {
614 >                    if (tabAt(tab, i) == f) {
615                          validated = true;
616 <                        Node pred = null;
583 <                        do {
616 >                        for (Node e = f, pred = null;;) {
617                              Object ek, ev;
618 <                            if (e.hash == h &&
619 <                                ((ek = e.key) == k || k.equals(ek)) &&
620 <                                ((ev = e.val) != null)) {
618 >                            if ((e.hash & HASH_BITS) == h &&
619 >                                ((ev = e.val) != null) &&
620 >                                ((ek = e.key) == k || k.equals(ek))) {
621                                  if (cv == null || cv == ev || cv.equals(ev)) {
622                                      oldVal = ev;
623                                      if ((e.val = v) == null) {
# Line 598 | Line 631 | public class ConcurrentHashMapV8<K, V>
631                                  }
632                                  break;
633                              }
634 <                        } while ((e = (pred = e).next) != null);
634 >                            pred = e;
635 >                            if ((e = e.next) == null)
636 >                                break;
637 >                        }
638 >                    }
639 >                } finally {
640 >                    if (!f.casHash(fh | LOCKED, fh)) {
641 >                        f.hash = fh;
642 >                        synchronized(f) { f.notifyAll(); };
643                      }
644                  }
645                  if (validated) {
646                      if (deleted)
647                          counter.decrement();
648 <                    return oldVal;
648 >                    break;
649                  }
650              }
651          }
652 +        return oldVal;
653      }
654  
655      /** Implementation for computeIfAbsent and compute. Like put, but messier. */
656 +    // Todo: Somehow reinstate non-termination check
657      @SuppressWarnings("unchecked")
658      private final V internalCompute(K k,
659 <                                    MappingFunction<? super K, ? extends V> f,
659 >                                    MappingFunction<? super K, ? extends V> fn,
660                                      boolean replace) {
661          int h = spread(k.hashCode());
662          V val = null;
663          boolean added = false;
664          Node[] tab = table;
665          outer:for (;;) {
666 <            Node e; int i; Object ek, ev;
666 >            Node f; int i, fh; Object fk, fv;
667              if (tab == null)
668 <                tab = growTable();
669 <            else if ((e = tabAt(tab, i = (tab.length - 1) & h)) == null) {
670 <                Node node = new Node(h, k, null, null);
668 >                tab = initTable();
669 >            else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) {
670 >                Node node = new Node(fh = h | LOCKED, k, null, null);
671                  boolean validated = false;
672 <                synchronized (node) {  // must lock while computing value
673 <                    if (casTabAt(tab, i, null, node)) {
674 <                        validated = true;
675 <                        try {
676 <                            val = f.map(k);
677 <                            if (val != null) {
678 <                                node.val = val;
679 <                                added = true;
680 <                            }
681 <                        } finally {
682 <                            if (!added)
683 <                                setTabAt(tab, i, null);
672 >                if (casTabAt(tab, i, null, node)) {
673 >                    validated = true;
674 >                    try {
675 >                        val = fn.map(k);
676 >                        if (val != null) {
677 >                            node.val = val;
678 >                            added = true;
679 >                        }
680 >                    } finally {
681 >                        if (!added)
682 >                            setTabAt(tab, i, null);
683 >                        if (!node.casHash(fh, h)) {
684 >                            node.hash = h;
685 >                            synchronized(node) { node.notifyAll(); };
686                          }
687                      }
688                  }
689                  if (validated)
690                      break;
691              }
692 <            else if (e.hash < 0)
693 <                tab = (Node[])e.key;
694 <            else if (!replace && e.hash == h && (ev = e.val) != null &&
695 <                     ((ek = e.key) == k || k.equals(ek))) {
696 <                if (tabAt(tab, i) == e) {
697 <                    val = (V)ev;
692 >            else if ((fh = f.hash) == MOVED)
693 >                tab = (Node[])f.key;
694 >            else if (!replace && (fh & HASH_BITS) == h && (fv = f.val) != null &&
695 >                     ((fk = f.key) == k || k.equals(fk))) {
696 >                if (tabAt(tab, i) == f) {
697 >                    val = (V)fv;
698                      break;
699                  }
700              }
701 <            else if (Thread.holdsLock(e))
702 <                throw new IllegalStateException("Recursive map computation");
703 <            else {
701 >            else if ((fh & LOCKED) != 0)
702 >                f.tryAwaitLock(tab, i);
703 >            else if (f.casHash(fh, fh | LOCKED)) {
704                  boolean validated = false;
705                  boolean checkSize = false;
706 <                synchronized (e) {
707 <                    if (tabAt(tab, i) == e) {
706 >                try {
707 >                    if (tabAt(tab, i) == f) {
708                          validated = true;
709 <                        for (Node first = e;;) {
710 <                            if (e.hash == h &&
711 <                                ((ek = e.key) == k || k.equals(ek)) &&
712 <                                ((ev = e.val) != null)) {
713 <                                Object fv;
714 <                                if (replace && (fv = f.map(k)) != null)
715 <                                    ev = e.val = fv;
709 >                        for (Node e = f;;) {
710 >                            Object ek, ev, v;
711 >                            if ((e.hash & HASH_BITS) == h &&
712 >                                (ev = e.val) != null &&
713 >                                ((ek = e.key) == k || k.equals(ek))) {
714 >                                if (replace && (v = fn.map(k)) != null)
715 >                                    ev = e.val = v;
716                                  val = (V)ev;
717                                  break;
718                              }
719                              Node last = e;
720                              if ((e = e.next) == null) {
721 <                                if ((val = f.map(k)) != null) {
721 >                                if ((val = fn.map(k)) != null) {
722                                      last.next = new Node(h, k, val, null);
723                                      added = true;
724 <                                    if (last != first || tab.length <= 64)
724 >                                    if (last != f || tab.length <= 64)
725                                          checkSize = true;
726                                  }
727                                  break;
728                              }
729                          }
730                      }
731 +                } finally {
732 +                    if (!f.casHash(fh | LOCKED, fh)) {
733 +                        f.hash = fh;
734 +                        synchronized(f) { f.notifyAll(); };
735 +                    }
736                  }
737                  if (validated) {
738 +                    int sc;
739                      if (checkSize && tab.length < MAXIMUM_CAPACITY &&
740 <                        resizing == 0 && counter.sum() >= threshold)
740 >                        (sc = sizeCtl) >= 0 && counter.sum() >= (long)sc)
741                          growTable();
742                      break;
743                  }
# Line 705 | Line 756 | public class ConcurrentHashMapV8<K, V>
756          int i = 0;
757          Node[] tab = table;
758          while (tab != null && i < tab.length) {
759 <            Node e = tabAt(tab, i);
760 <            if (e == null)
759 >            int fh;
760 >            Node f = tabAt(tab, i);
761 >            if (f == null)
762                  ++i;
763 <            else if (e.hash < 0)
764 <                tab = (Node[])e.key;
765 <            else {
763 >            else if ((fh = f.hash) == MOVED)
764 >                tab = (Node[])f.key;
765 >            else if ((fh & LOCKED) != 0)
766 >                f.tryAwaitLock(tab, i);
767 >            else if (f.casHash(fh, fh | LOCKED)) {
768                  boolean validated = false;
769 <                synchronized (e) {
770 <                    if (tabAt(tab, i) == e) {
769 >                try {
770 >                    if (tabAt(tab, i) == f) {
771                          validated = true;
772 <                        Node en;
719 <                        do {
720 <                            en = e.next;
772 >                        for (Node e = f; e != null; e = e.next) {
773                              if (e.val != null) { // currently always true
774                                  e.val = null;
775                                  --delta;
776                              }
777 <                        } while ((e = en) != null);
777 >                        }
778                          setTabAt(tab, i, null);
779                      }
780 +                } finally {
781 +                    if (!f.casHash(fh | LOCKED, fh)) {
782 +                        f.hash = fh;
783 +                        synchronized(f) { f.notifyAll(); };
784 +                    }
785                  }
786                  if (validated)
787                      ++i;
# Line 733 | Line 790 | public class ConcurrentHashMapV8<K, V>
790          counter.add(delta);
791      }
792  
793 +    /* ----------------Table Initialization and Resizing -------------- */
794 +
795 +    /**
796 +     * Returns a power of two table size for the given desired capacity.
797 +     * See Hackers Delight, sec 3.2
798 +     */
799 +    private static final int tableSizeFor(int c) {
800 +        int n = c - 1;
801 +        n |= n >>> 1;
802 +        n |= n >>> 2;
803 +        n |= n >>> 4;
804 +        n |= n >>> 8;
805 +        n |= n >>> 16;
806 +        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
807 +    }
808 +
809 +    /**
810 +     * Initializes table, using the size recorded in sizeCtl.
811 +     */
812 +    private final Node[] initTable() {
813 +        Node[] tab; int sc;
814 +        while ((tab = table) == null) {
815 +            if ((sc = sizeCtl) < 0)
816 +                Thread.yield(); // lost initialization race; just spin
817 +            else if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) {
818 +                try {
819 +                    if ((tab = table) == null) {
820 +                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
821 +                        tab = table = new Node[n];
822 +                        sc = n - (n >>> 2) - 1;
823 +                    }
824 +                } finally {
825 +                    sizeCtl = sc;
826 +                }
827 +                break;
828 +            }
829 +        }
830 +        return tab;
831 +    }
832 +
833 +    /**
834 +     * If not already resizing, creates next table and transfers bins.
835 +     * Rechecks occupancy after a transfer to see if another resize is
836 +     * already needed because resizings are lagging additions.
837 +     */
838 +    private final void growTable() {
839 +        int sc = sizeCtl;
840 +        if (sc >= 0 && UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) {
841 +            try {
842 +                Node[] tab; int n;
843 +                while ((tab = table) != null &&
844 +                       (n = tab.length) > 0 && n < MAXIMUM_CAPACITY &&
845 +                       counter.sum() >= (long)sc) {
846 +                    table = rebuild(tab);
847 +                    sc = (n << 1) - (n >>> 1) - 1;
848 +                }
849 +            } finally {
850 +                sizeCtl = sc;
851 +            }
852 +        }
853 +    }
854 +
855 +    /*
856 +     * Moves and/or copies the nodes in each bin to new table. See
857 +     * above for explanation.
858 +     *
859 +     * @return the new table
860 +     */
861 +    private static final Node[] rebuild(Node[] tab) {
862 +        int n = tab.length;
863 +        Node[] nextTab = new Node[n << 1];
864 +        Node fwd = new Node(MOVED, nextTab, null, null);
865 +        int[] buffer = null;       // holds bins to revisit; null until needed
866 +        Node rev = null;           // reverse forwarder; null until needed
867 +        int nbuffered = 0;         // the number of bins in buffer list
868 +        int bufferIndex = 0;       // buffer index of current buffered bin
869 +        int bin = n - 1;           // current non-buffered bin or -1 if none
870 +
871 +        for (int i = bin;;) {      // start upwards sweep
872 +            int fh; Node f;
873 +            if ((f = tabAt(tab, i)) == null) {
874 +                if (bin >= 0) {    // no lock needed (or available)
875 +                    if (!casTabAt(tab, i, f, fwd))
876 +                        continue;
877 +                }
878 +                else {             // transiently use a locked forwarding node
879 +                    Node g =  new Node(MOVED|LOCKED, nextTab, null, null);
880 +                    if (!casTabAt(tab, i, f, g))
881 +                        continue;
882 +                    setTabAt(nextTab, i, null);
883 +                    setTabAt(nextTab, i + n, null);
884 +                    setTabAt(tab, i, fwd);
885 +                    if (!g.casHash(MOVED|LOCKED, MOVED)) {
886 +                        g.hash = MOVED;
887 +                        synchronized(g) { g.notifyAll(); }
888 +                    }
889 +                }
890 +            }
891 +            else if (((fh = f.hash) & LOCKED) == 0 && f.casHash(fh, fh|LOCKED)) {
892 +                boolean validated = false;
893 +                try {              // split to lo and hi lists; copying as needed
894 +                    if (tabAt(tab, i) == f) {
895 +                        validated = true;
896 +                        Node e = f, lastRun = f;
897 +                        Node lo = null, hi = null;
898 +                        int runBit = e.hash & n;
899 +                        for (Node p = e.next; p != null; p = p.next) {
900 +                            int b = p.hash & n;
901 +                            if (b != runBit) {
902 +                                runBit = b;
903 +                                lastRun = p;
904 +                            }
905 +                        }
906 +                        if (runBit == 0)
907 +                            lo = lastRun;
908 +                        else
909 +                            hi = lastRun;
910 +                        for (Node p = e; p != lastRun; p = p.next) {
911 +                            int ph = p.hash & HASH_BITS;
912 +                            Object pk = p.key, pv = p.val;
913 +                            if ((ph & n) == 0)
914 +                                lo = new Node(ph, pk, pv, lo);
915 +                            else
916 +                                hi = new Node(ph, pk, pv, hi);
917 +                        }
918 +                        setTabAt(nextTab, i, lo);
919 +                        setTabAt(nextTab, i + n, hi);
920 +                        setTabAt(tab, i, fwd);
921 +                    }
922 +                } finally {
923 +                    if (!f.casHash(fh | LOCKED, fh)) {
924 +                        f.hash = fh;
925 +                        synchronized(f) { f.notifyAll(); };
926 +                    }
927 +                }
928 +                if (!validated)
929 +                    continue;
930 +            }
931 +            else {
932 +                if (buffer == null) // initialize buffer for revisits
933 +                    buffer = new int[TRANSFER_BUFFER_SIZE];
934 +                if (bin < 0 && bufferIndex > 0) {
935 +                    int j = buffer[--bufferIndex];
936 +                    buffer[bufferIndex] = i;
937 +                    i = j;         // swap with another bin
938 +                    continue;
939 +                }
940 +                if (bin < 0 || nbuffered >= TRANSFER_BUFFER_SIZE) {
941 +                    f.tryAwaitLock(tab, i);
942 +                    continue;      // no other options -- block
943 +                }
944 +                if (rev == null)   // initialize reverse-forwarder
945 +                    rev = new Node(MOVED, tab, null, null);
946 +                if (tabAt(tab, i) != f || (f.hash & LOCKED) == 0)
947 +                    continue;      // recheck before adding to list
948 +                buffer[nbuffered++] = i;
949 +                setTabAt(nextTab, i, rev);     // install place-holders
950 +                setTabAt(nextTab, i + n, rev);
951 +            }
952 +
953 +            if (bin > 0)
954 +                i = --bin;
955 +            else if (buffer != null && nbuffered > 0) {
956 +                bin = -1;
957 +                i = buffer[bufferIndex = --nbuffered];
958 +            }
959 +            else
960 +                return nextTab;
961 +        }
962 +    }
963 +
964      /* ----------------Table Traversal -------------- */
965  
966      /**
# Line 748 | Line 976 | public class ConcurrentHashMapV8<K, V>
976       * valid.
977       *
978       * Internal traversals directly access these fields, as in:
979 <     * {@code while (it.next != null) { process(nextKey); it.advance(); }}
979 >     * {@code while (it.next != null) { process(it.nextKey); it.advance(); }}
980       *
981       * Exported iterators (subclasses of ViewIterator) extract key,
982       * value, or key-value pairs as return values of Iterator.next(),
983 <     * and encapulate the it.next check as hasNext();
983 >     * and encapsulate the it.next check as hasNext();
984       *
985       * The iterator visits each valid node that was reachable upon
986       * iterator construction once. It might miss some that were added
# Line 797 | Line 1025 | public class ConcurrentHashMapV8<K, V>
1025          InternalIterator(Node[] tab, int lo, int hi) {
1026              this.tab = tab;
1027              baseSize = (tab == null) ? 0 : tab.length;
1028 <            baseLimit = (hi <= baseSize)? hi : baseSize;
1028 >            baseLimit = (hi <= baseSize) ? hi : baseSize;
1029              index = baseIndex = lo;
1030              next = null;
1031              advance();
# Line 807 | Line 1035 | public class ConcurrentHashMapV8<K, V>
1035          final void advance() {
1036              Node e = last = next;
1037              outer: do {
1038 <                if (e != null)                   // pass used or skipped node
1038 >                if (e != null)                  // advance past used/skipped node
1039                      e = e.next;
1040 <                while (e == null) {              // get to next non-null bin
1041 <                    Node[] t; int b, i, n;       // checks must use locals
1040 >                while (e == null) {             // get to next non-null bin
1041 >                    Node[] t; int b, i, n;      // checks must use locals
1042                      if ((b = baseIndex) >= baseLimit || (i = index) < 0 ||
1043                          (t = tab) == null || i >= (n = t.length))
1044                          break outer;
1045 <                    else if ((e = tabAt(t, i)) != null && e.hash < 0)
1046 <                        tab = (Node[])e.key;     // restarts due to null val
1047 <                    else                         // visit upper slots if present
1045 >                    else if ((e = tabAt(t, i)) != null && e.hash == MOVED)
1046 >                        tab = (Node[])e.key;    // restarts due to null val
1047 >                    else                        // visit upper slots if present
1048                          index = (i += baseSize) < n ? i : (baseIndex = b + 1);
1049                  }
1050                  nextKey = e.key;
1051 <            } while ((nextVal = e.val) == null); // skip deleted or special nodes
1051 >            } while ((nextVal = e.val) == null);// skip deleted or special nodes
1052              next = e;
1053          }
1054      }
# Line 828 | Line 1056 | public class ConcurrentHashMapV8<K, V>
1056      /* ---------------- Public operations -------------- */
1057  
1058      /**
1059 <     * Creates a new, empty map with the specified initial
832 <     * capacity, load factor and concurrency level.
833 <     *
834 <     * @param initialCapacity the initial capacity. The implementation
835 <     * performs internal sizing to accommodate this many elements.
836 <     * @param loadFactor  the load factor threshold, used to control resizing.
837 <     * Resizing may be performed when the average number of elements per
838 <     * bin exceeds this threshold.
839 <     * @param concurrencyLevel the estimated number of concurrently
840 <     * updating threads. The implementation may use this value as
841 <     * a sizing hint.
842 <     * @throws IllegalArgumentException if the initial capacity is
843 <     * negative or the load factor or concurrencyLevel are
844 <     * nonpositive.
1059 >     * Creates a new, empty map with the default initial table size (16),
1060       */
1061 <    public ConcurrentHashMapV8(int initialCapacity,
847 <                               float loadFactor, int concurrencyLevel) {
848 <        if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
849 <            throw new IllegalArgumentException();
850 <        int cap = tableSizeFor(initialCapacity);
1061 >    public ConcurrentHashMapV8() {
1062          this.counter = new LongAdder();
852        this.loadFactor = loadFactor;
853        this.targetCapacity = cap;
1063      }
1064  
1065      /**
1066 <     * Creates a new, empty map with the specified initial capacity
1067 <     * and load factor and with the default concurrencyLevel (16).
1066 >     * Creates a new, empty map with an initial table size
1067 >     * accommodating the specified number of elements without the need
1068 >     * to dynamically resize.
1069       *
1070       * @param initialCapacity The implementation performs internal
1071       * sizing to accommodate this many elements.
862     * @param loadFactor  the load factor threshold, used to control resizing.
863     * Resizing may be performed when the average number of elements per
864     * bin exceeds this threshold.
1072       * @throws IllegalArgumentException if the initial capacity of
1073 <     * elements is negative or the load factor is nonpositive
867 <     *
868 <     * @since 1.6
1073 >     * elements is negative
1074       */
1075 <    public ConcurrentHashMapV8(int initialCapacity, float loadFactor) {
1076 <        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
1075 >    public ConcurrentHashMapV8(int initialCapacity) {
1076 >        if (initialCapacity < 0)
1077 >            throw new IllegalArgumentException();
1078 >        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
1079 >                   MAXIMUM_CAPACITY :
1080 >                   tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
1081 >        this.counter = new LongAdder();
1082 >        this.sizeCtl = cap;
1083      }
1084  
1085      /**
1086 <     * Creates a new, empty map with the specified initial capacity,
876 <     * and with default load factor (0.75) and concurrencyLevel (16).
1086 >     * Creates a new map with the same mappings as the given map.
1087       *
1088 <     * @param initialCapacity the initial capacity. The implementation
879 <     * performs internal sizing to accommodate this many elements.
880 <     * @throws IllegalArgumentException if the initial capacity of
881 <     * elements is negative.
1088 >     * @param m the map
1089       */
1090 <    public ConcurrentHashMapV8(int initialCapacity) {
1091 <        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
1090 >    public ConcurrentHashMapV8(Map<? extends K, ? extends V> m) {
1091 >        this.counter = new LongAdder();
1092 >        this.sizeCtl = DEFAULT_CAPACITY;
1093 >        putAll(m);
1094      }
1095  
1096      /**
1097 <     * Creates a new, empty map with a default initial capacity (16),
1098 <     * load factor (0.75) and concurrencyLevel (16).
1097 >     * Creates a new, empty map with an initial table size based on
1098 >     * the given number of elements ({@code initialCapacity}) and
1099 >     * initial table density ({@code loadFactor}).
1100 >     *
1101 >     * @param initialCapacity the initial capacity. The implementation
1102 >     * performs internal sizing to accommodate this many elements,
1103 >     * given the specified load factor.
1104 >     * @param loadFactor the load factor (table density) for
1105 >     * establishing the initial table size
1106 >     * @throws IllegalArgumentException if the initial capacity of
1107 >     * elements is negative or the load factor is nonpositive
1108 >     *
1109 >     * @since 1.6
1110       */
1111 <    public ConcurrentHashMapV8() {
1112 <        this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
1111 >    public ConcurrentHashMapV8(int initialCapacity, float loadFactor) {
1112 >        this(initialCapacity, loadFactor, 1);
1113      }
1114  
1115      /**
1116 <     * Creates a new map with the same mappings as the given map.
1117 <     * The map is created with a capacity of 1.5 times the number
1118 <     * of mappings in the given map or 16 (whichever is greater),
1119 <     * and a default load factor (0.75) and concurrencyLevel (16).
1116 >     * Creates a new, empty map with an initial table size based on
1117 >     * the given number of elements ({@code initialCapacity}), table
1118 >     * density ({@code loadFactor}), and number of concurrently
1119 >     * updating threads ({@code concurrencyLevel}).
1120       *
1121 <     * @param m the map
1121 >     * @param initialCapacity the initial capacity. The implementation
1122 >     * performs internal sizing to accommodate this many elements,
1123 >     * given the specified load factor.
1124 >     * @param loadFactor the load factor (table density) for
1125 >     * establishing the initial table size
1126 >     * @param concurrencyLevel the estimated number of concurrently
1127 >     * updating threads. The implementation may use this value as
1128 >     * a sizing hint.
1129 >     * @throws IllegalArgumentException if the initial capacity is
1130 >     * negative or the load factor or concurrencyLevel are
1131 >     * nonpositive
1132       */
1133 <    public ConcurrentHashMapV8(Map<? extends K, ? extends V> m) {
1134 <        this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
1135 <        putAll(m);
1133 >    public ConcurrentHashMapV8(int initialCapacity,
1134 >                               float loadFactor, int concurrencyLevel) {
1135 >        if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
1136 >            throw new IllegalArgumentException();
1137 >        if (initialCapacity < concurrencyLevel)   // Use at least as many bins
1138 >            initialCapacity = concurrencyLevel;   // as estimated threads
1139 >        long size = (long)(1.0 + (long)initialCapacity / loadFactor);
1140 >        int cap =  ((size >= (long)MAXIMUM_CAPACITY) ?
1141 >                    MAXIMUM_CAPACITY: tableSizeFor((int)size));
1142 >        this.counter = new LongAdder();
1143 >        this.sizeCtl = cap;
1144      }
1145  
1146      /**
# Line 917 | Line 1155 | public class ConcurrentHashMapV8<K, V>
1155       */
1156      public int size() {
1157          long n = counter.sum();
1158 <        return ((n < 0L)? 0 :
1159 <                (n > (long)Integer.MAX_VALUE)? Integer.MAX_VALUE :
1158 >        return ((n < 0L) ? 0 :
1159 >                (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE :
1160                  (int)n);
1161      }
1162  
1163 +    final long longSize() { // accurate version of size needed for views
1164 +        long n = counter.sum();
1165 +        return (n < 0L) ? 0L : n;
1166 +    }
1167 +
1168      /**
1169       * Returns the value to which the specified key is mapped,
1170       * or {@code null} if this map contains no mapping for the key.
# Line 946 | Line 1189 | public class ConcurrentHashMapV8<K, V>
1189       * @param  key   possible key
1190       * @return {@code true} if and only if the specified object
1191       *         is a key in this table, as determined by the
1192 <     *         {@code equals} method; {@code false} otherwise.
1192 >     *         {@code equals} method; {@code false} otherwise
1193       * @throws NullPointerException if the specified key is null
1194       */
1195      public boolean containsKey(Object key) {
# Line 1042 | Line 1285 | public class ConcurrentHashMapV8<K, V>
1285          if (m == null)
1286              throw new NullPointerException();
1287          /*
1288 <         * If uninitialized, try to adjust targetCapacity to
1046 <         * accommodate the given number of elements.
1288 >         * If uninitialized, try to preallocate big enough table
1289           */
1290          if (table == null) {
1291              int size = m.size();
1292 <            int cap = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
1293 <                tableSizeFor(size + (size >>> 1));
1294 <            if (cap > targetCapacity)
1295 <                targetCapacity = cap;
1292 >            int n = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
1293 >                tableSizeFor(size + (size >>> 1) + 1);
1294 >            int sc = sizeCtl;
1295 >            if (n < sc)
1296 >                n = sc;
1297 >            if (sc >= 0 &&
1298 >                UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) {
1299 >                try {
1300 >                    if (table == null) {
1301 >                        table = new Node[n];
1302 >                        sc = n - (n >>> 2) - 1;
1303 >                    }
1304 >                } finally {
1305 >                    sizeCtl = sc;
1306 >                }
1307 >            }
1308 >        }
1309 >        for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
1310 >            Object ek = e.getKey(), ev = e.getValue();
1311 >            if (ek == null || ev == null)
1312 >                throw new NullPointerException();
1313 >            internalPut(ek, ev, true);
1314          }
1055        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
1056            put(e.getKey(), e.getValue());
1315      }
1316  
1317      /**
# Line 1083 | Line 1341 | public class ConcurrentHashMapV8<K, V>
1341       * @param mappingFunction the function to compute a value
1342       * @return the current (existing or computed) value associated with
1343       *         the specified key, or {@code null} if the computation
1344 <     *         returned {@code null}.
1344 >     *         returned {@code null}
1345       * @throws NullPointerException if the specified key or mappingFunction
1346 <     *         is null,
1346 >     *         is null
1347       * @throws IllegalStateException if the computation detectably
1348       *         attempts a recursive update to this map that would
1349 <     *         otherwise never complete.
1349 >     *         otherwise never complete
1350       * @throws RuntimeException or Error if the mappingFunction does so,
1351 <     *         in which case the mapping is left unestablished.
1351 >     *         in which case the mapping is left unestablished
1352       */
1353      public V computeIfAbsent(K key, MappingFunction<? super K, ? extends V> mappingFunction) {
1354          if (key == null || mappingFunction == null)
# Line 1120 | Line 1378 | public class ConcurrentHashMapV8<K, V>
1378       * @param mappingFunction the function to compute a value
1379       * @return the current value associated with
1380       *         the specified key, or {@code null} if the computation
1381 <     *         returned {@code null} and the value was not otherwise present.
1381 >     *         returned {@code null} and the value was not otherwise present
1382       * @throws NullPointerException if the specified key or mappingFunction
1383 <     *         is null,
1383 >     *         is null
1384       * @throws IllegalStateException if the computation detectably
1385       *         attempts a recursive update to this map that would
1386 <     *         otherwise never complete.
1386 >     *         otherwise never complete
1387       * @throws RuntimeException or Error if the mappingFunction does so,
1388 <     *         in which case the mapping is unchanged.
1388 >     *         in which case the mapping is unchanged
1389       */
1390      public V compute(K key, MappingFunction<? super K, ? extends V> mappingFunction) {
1391          if (key == null || mappingFunction == null)
# Line 1428 | Line 1686 | public class ConcurrentHashMapV8<K, V>
1686              Object k = nextKey;
1687              Object v = nextVal;
1688              advance();
1689 <            return new WriteThroughEntry<K,V>(map, (K)k, (V)v);
1689 >            return new WriteThroughEntry<K,V>((K)k, (V)v, map);
1690 >        }
1691 >    }
1692 >
1693 >    static final class SnapshotEntryIterator<K,V> extends ViewIterator<K,V>
1694 >        implements Iterator<Map.Entry<K,V>> {
1695 >        SnapshotEntryIterator(ConcurrentHashMapV8<K, V> map) { super(map); }
1696 >
1697 >        @SuppressWarnings("unchecked")
1698 >        public final Map.Entry<K,V> next() {
1699 >            if (next == null)
1700 >                throw new NoSuchElementException();
1701 >            Object k = nextKey;
1702 >            Object v = nextVal;
1703 >            advance();
1704 >            return new SnapshotEntry<K,V>((K)k, (V)v);
1705          }
1706      }
1707  
1708      /**
1709 <     * Custom Entry class used by EntryIterator.next(), that relays
1437 <     * setValue changes to the underlying map.
1709 >     * Base of writeThrough and Snapshot entry classes
1710       */
1711 <    static final class WriteThroughEntry<K,V> implements Map.Entry<K, V> {
1440 <        final ConcurrentHashMapV8<K, V> map;
1711 >    static abstract class MapEntry<K,V> implements Map.Entry<K, V> {
1712          final K key; // non-null
1713          V val;       // non-null
1714 <        WriteThroughEntry(ConcurrentHashMapV8<K, V> map, K key, V val) {
1444 <            this.map = map; this.key = key; this.val = val;
1445 <        }
1446 <
1714 >        MapEntry(K key, V val)        { this.key = key; this.val = val; }
1715          public final K getKey()       { return key; }
1716          public final V getValue()     { return val; }
1717          public final int hashCode()   { return key.hashCode() ^ val.hashCode(); }
# Line 1458 | Line 1726 | public class ConcurrentHashMapV8<K, V>
1726                      (v == val || v.equals(val)));
1727          }
1728  
1729 +        public abstract V setValue(V value);
1730 +    }
1731 +
1732 +    /**
1733 +     * Entry used by EntryIterator.next(), that relays setValue
1734 +     * changes to the underlying map.
1735 +     */
1736 +    static final class WriteThroughEntry<K,V> extends MapEntry<K,V>
1737 +        implements Map.Entry<K, V> {
1738 +        final ConcurrentHashMapV8<K, V> map;
1739 +        WriteThroughEntry(K key, V val, ConcurrentHashMapV8<K, V> map) {
1740 +            super(key, val);
1741 +            this.map = map;
1742 +        }
1743 +
1744          /**
1745           * Sets our entry's value and writes through to the map. The
1746           * value to return is somewhat arbitrary here. Since a
# Line 1476 | Line 1759 | public class ConcurrentHashMapV8<K, V>
1759          }
1760      }
1761  
1762 +    /**
1763 +     * Internal version of entry, that doesn't write though changes
1764 +     */
1765 +    static final class SnapshotEntry<K,V> extends MapEntry<K,V>
1766 +        implements Map.Entry<K, V> {
1767 +        SnapshotEntry(K key, V val) { super(key, val); }
1768 +        public final V setValue(V value) { // only locally update
1769 +            if (value == null) throw new NullPointerException();
1770 +            V v = val;
1771 +            val = value;
1772 +            return v;
1773 +        }
1774 +    }
1775 +
1776      /* ----------------Views -------------- */
1777  
1778 <    /*
1779 <     * These currently just extend java.util.AbstractX classes, but
1780 <     * may need a new custom base to support partitioned traversal.
1778 >    /**
1779 >     * Base class for views. This is done mainly to allow adding
1780 >     * customized parallel traversals (not yet implemented.)
1781       */
1782 <
1486 <    static final class KeySet<K,V> extends AbstractSet<K> {
1782 >    static abstract class MapView<K, V> {
1783          final ConcurrentHashMapV8<K, V> map;
1784 <        KeySet(ConcurrentHashMapV8<K, V> map)   { this.map = map; }
1489 <
1784 >        MapView(ConcurrentHashMapV8<K, V> map)  { this.map = map; }
1785          public final int size()                 { return map.size(); }
1786          public final boolean isEmpty()          { return map.isEmpty(); }
1787          public final void clear()               { map.clear(); }
1788 +
1789 +        // implementations below rely on concrete classes supplying these
1790 +        abstract Iterator<?> iter();
1791 +        abstract public boolean contains(Object o);
1792 +        abstract public boolean remove(Object o);
1793 +
1794 +        private static final String oomeMsg = "Required array size too large";
1795 +
1796 +        public final Object[] toArray() {
1797 +            long sz = map.longSize();
1798 +            if (sz > (long)(MAX_ARRAY_SIZE))
1799 +                throw new OutOfMemoryError(oomeMsg);
1800 +            int n = (int)sz;
1801 +            Object[] r = new Object[n];
1802 +            int i = 0;
1803 +            Iterator<?> it = iter();
1804 +            while (it.hasNext()) {
1805 +                if (i == n) {
1806 +                    if (n >= MAX_ARRAY_SIZE)
1807 +                        throw new OutOfMemoryError(oomeMsg);
1808 +                    if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
1809 +                        n = MAX_ARRAY_SIZE;
1810 +                    else
1811 +                        n += (n >>> 1) + 1;
1812 +                    r = Arrays.copyOf(r, n);
1813 +                }
1814 +                r[i++] = it.next();
1815 +            }
1816 +            return (i == n) ? r : Arrays.copyOf(r, i);
1817 +        }
1818 +
1819 +        @SuppressWarnings("unchecked")
1820 +        public final <T> T[] toArray(T[] a) {
1821 +            long sz = map.longSize();
1822 +            if (sz > (long)(MAX_ARRAY_SIZE))
1823 +                throw new OutOfMemoryError(oomeMsg);
1824 +            int m = (int)sz;
1825 +            T[] r = (a.length >= m) ? a :
1826 +                (T[])java.lang.reflect.Array
1827 +                .newInstance(a.getClass().getComponentType(), m);
1828 +            int n = r.length;
1829 +            int i = 0;
1830 +            Iterator<?> it = iter();
1831 +            while (it.hasNext()) {
1832 +                if (i == n) {
1833 +                    if (n >= MAX_ARRAY_SIZE)
1834 +                        throw new OutOfMemoryError(oomeMsg);
1835 +                    if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
1836 +                        n = MAX_ARRAY_SIZE;
1837 +                    else
1838 +                        n += (n >>> 1) + 1;
1839 +                    r = Arrays.copyOf(r, n);
1840 +                }
1841 +                r[i++] = (T)it.next();
1842 +            }
1843 +            if (a == r && i < n) {
1844 +                r[i] = null; // null-terminate
1845 +                return r;
1846 +            }
1847 +            return (i == n) ? r : Arrays.copyOf(r, i);
1848 +        }
1849 +
1850 +        public final int hashCode() {
1851 +            int h = 0;
1852 +            for (Iterator<?> it = iter(); it.hasNext();)
1853 +                h += it.next().hashCode();
1854 +            return h;
1855 +        }
1856 +
1857 +        public final String toString() {
1858 +            StringBuilder sb = new StringBuilder();
1859 +            sb.append('[');
1860 +            Iterator<?> it = iter();
1861 +            if (it.hasNext()) {
1862 +                for (;;) {
1863 +                    Object e = it.next();
1864 +                    sb.append(e == this ? "(this Collection)" : e);
1865 +                    if (!it.hasNext())
1866 +                        break;
1867 +                    sb.append(',').append(' ');
1868 +                }
1869 +            }
1870 +            return sb.append(']').toString();
1871 +        }
1872 +
1873 +        public final boolean containsAll(Collection<?> c) {
1874 +            if (c != this) {
1875 +                for (Iterator<?> it = c.iterator(); it.hasNext();) {
1876 +                    Object e = it.next();
1877 +                    if (e == null || !contains(e))
1878 +                        return false;
1879 +                }
1880 +            }
1881 +            return true;
1882 +        }
1883 +
1884 +        public final boolean removeAll(Collection c) {
1885 +            boolean modified = false;
1886 +            for (Iterator<?> it = iter(); it.hasNext();) {
1887 +                if (c.contains(it.next())) {
1888 +                    it.remove();
1889 +                    modified = true;
1890 +                }
1891 +            }
1892 +            return modified;
1893 +        }
1894 +
1895 +        public final boolean retainAll(Collection<?> c) {
1896 +            boolean modified = false;
1897 +            for (Iterator<?> it = iter(); it.hasNext();) {
1898 +                if (!c.contains(it.next())) {
1899 +                    it.remove();
1900 +                    modified = true;
1901 +                }
1902 +            }
1903 +            return modified;
1904 +        }
1905 +
1906 +    }
1907 +
1908 +    static final class KeySet<K,V> extends MapView<K,V> implements Set<K> {
1909 +        KeySet(ConcurrentHashMapV8<K, V> map)   { super(map); }
1910          public final boolean contains(Object o) { return map.containsKey(o); }
1911          public final boolean remove(Object o)   { return map.remove(o) != null; }
1912 +
1913          public final Iterator<K> iterator() {
1914              return new KeyIterator<K,V>(map);
1915          }
1916 +        final Iterator<?> iter() {
1917 +            return new KeyIterator<K,V>(map);
1918 +        }
1919 +        public final boolean add(K e) {
1920 +            throw new UnsupportedOperationException();
1921 +        }
1922 +        public final boolean addAll(Collection<? extends K> c) {
1923 +            throw new UnsupportedOperationException();
1924 +        }
1925 +        public boolean equals(Object o) {
1926 +            Set<?> c;
1927 +            return ((o instanceof Set) &&
1928 +                    ((c = (Set<?>)o) == this ||
1929 +                     (containsAll(c) && c.containsAll(this))));
1930 +        }
1931      }
1932  
1933 <    static final class Values<K,V> extends AbstractCollection<V> {
1934 <        final ConcurrentHashMapV8<K, V> map;
1935 <        Values(ConcurrentHashMapV8<K, V> map)   { this.map = map; }
1503 <
1504 <        public final int size()                 { return map.size(); }
1505 <        public final boolean isEmpty()          { return map.isEmpty(); }
1506 <        public final void clear()               { map.clear(); }
1933 >    static final class Values<K,V> extends MapView<K,V>
1934 >        implements Collection<V>  {
1935 >        Values(ConcurrentHashMapV8<K, V> map)   { super(map); }
1936          public final boolean contains(Object o) { return map.containsValue(o); }
1937 +
1938 +        public final boolean remove(Object o) {
1939 +            if (o != null) {
1940 +                Iterator<V> it = new ValueIterator<K,V>(map);
1941 +                while (it.hasNext()) {
1942 +                    if (o.equals(it.next())) {
1943 +                        it.remove();
1944 +                        return true;
1945 +                    }
1946 +                }
1947 +            }
1948 +            return false;
1949 +        }
1950          public final Iterator<V> iterator() {
1951              return new ValueIterator<K,V>(map);
1952          }
1953 +        final Iterator<?> iter() {
1954 +            return new ValueIterator<K,V>(map);
1955 +        }
1956 +        public final boolean add(V e) {
1957 +            throw new UnsupportedOperationException();
1958 +        }
1959 +        public final boolean addAll(Collection<? extends V> c) {
1960 +            throw new UnsupportedOperationException();
1961 +        }
1962      }
1963  
1964 <    static final class EntrySet<K,V> extends AbstractSet<Map.Entry<K,V>> {
1965 <        final ConcurrentHashMapV8<K, V> map;
1966 <        EntrySet(ConcurrentHashMapV8<K, V> map) { this.map = map; }
1516 <
1517 <        public final int size()                 { return map.size(); }
1518 <        public final boolean isEmpty()          { return map.isEmpty(); }
1519 <        public final void clear()               { map.clear(); }
1520 <        public final Iterator<Map.Entry<K,V>> iterator() {
1521 <            return new EntryIterator<K,V>(map);
1522 <        }
1964 >    static final class EntrySet<K,V>  extends MapView<K,V>
1965 >        implements Set<Map.Entry<K,V>> {
1966 >        EntrySet(ConcurrentHashMapV8<K, V> map) { super(map); }
1967  
1968          public final boolean contains(Object o) {
1969              Object k, v, r; Map.Entry<?,?> e;
# Line 1537 | Line 1981 | public class ConcurrentHashMapV8<K, V>
1981                      (v = e.getValue()) != null &&
1982                      map.remove(k, v));
1983          }
1984 +
1985 +        public final Iterator<Map.Entry<K,V>> iterator() {
1986 +            return new EntryIterator<K,V>(map);
1987 +        }
1988 +        final Iterator<?> iter() {
1989 +            return new SnapshotEntryIterator<K,V>(map);
1990 +        }
1991 +        public final boolean add(Entry<K,V> e) {
1992 +            throw new UnsupportedOperationException();
1993 +        }
1994 +        public final boolean addAll(Collection<? extends Entry<K,V>> c) {
1995 +            throw new UnsupportedOperationException();
1996 +        }
1997 +        public boolean equals(Object o) {
1998 +            Set<?> c;
1999 +            return ((o instanceof Set) &&
2000 +                    ((c = (Set<?>)o) == this ||
2001 +                     (containsAll(c) && c.containsAll(this))));
2002 +        }
2003      }
2004  
2005      /* ---------------- Serialization Support -------------- */
# Line 1567 | Line 2030 | public class ConcurrentHashMapV8<K, V>
2030              segments = (Segment<K,V>[])
2031                  new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
2032              for (int i = 0; i < segments.length; ++i)
2033 <                segments[i] = new Segment<K,V>(DEFAULT_LOAD_FACTOR);
2033 >                segments[i] = new Segment<K,V>(LOAD_FACTOR);
2034          }
2035          s.defaultWriteObject();
2036          InternalIterator it = new InternalIterator(table);
# Line 1590 | Line 2053 | public class ConcurrentHashMapV8<K, V>
2053              throws java.io.IOException, ClassNotFoundException {
2054          s.defaultReadObject();
2055          this.segments = null; // unneeded
2056 <        // initalize transient final fields
2056 >        // initialize transient final field
2057          UNSAFE.putObjectVolatile(this, counterOffset, new LongAdder());
1595        UNSAFE.putFloatVolatile(this, loadFactorOffset, DEFAULT_LOAD_FACTOR);
1596        this.targetCapacity = DEFAULT_CAPACITY;
2058  
2059          // Create all nodes, then place in table once size is known
2060          long size = 0L;
# Line 1610 | Line 2071 | public class ConcurrentHashMapV8<K, V>
2071          }
2072          if (p != null) {
2073              boolean init = false;
2074 <            if (resizing == 0 &&
2075 <                UNSAFE.compareAndSwapInt(this, resizingOffset, 0, 1)) {
2074 >            int n;
2075 >            if (size >= (long)(MAXIMUM_CAPACITY >>> 1))
2076 >                n = MAXIMUM_CAPACITY;
2077 >            else {
2078 >                int sz = (int)size;
2079 >                n = tableSizeFor(sz + (sz >>> 1) + 1);
2080 >            }
2081 >            int sc = sizeCtl;
2082 >            if (n > sc &&
2083 >                UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) {
2084                  try {
2085                      if (table == null) {
2086                          init = true;
1618                        int n;
1619                        if (size >= (long)(MAXIMUM_CAPACITY >>> 1))
1620                            n = MAXIMUM_CAPACITY;
1621                        else {
1622                            int sz = (int)size;
1623                            n = tableSizeFor(sz + (sz >>> 1));
1624                        }
1625                        threshold = (n - (n >>> 2)) - THRESHOLD_OFFSET;
2087                          Node[] tab = new Node[n];
2088                          int mask = n - 1;
2089                          while (p != null) {
# Line 1634 | Line 2095 | public class ConcurrentHashMapV8<K, V>
2095                          }
2096                          table = tab;
2097                          counter.add(size);
2098 +                        sc = n - (n >>> 2) - 1;
2099                      }
2100                  } finally {
2101 <                    resizing = 0;
2101 >                    sizeCtl = sc;
2102                  }
2103              }
2104              if (!init) { // Can only happen if unsafely published.
# Line 1651 | Line 2113 | public class ConcurrentHashMapV8<K, V>
2113      // Unsafe mechanics
2114      private static final sun.misc.Unsafe UNSAFE;
2115      private static final long counterOffset;
2116 <    private static final long loadFactorOffset;
1655 <    private static final long resizingOffset;
2116 >    private static final long sizeCtlOffset;
2117      private static final long ABASE;
2118      private static final int ASHIFT;
2119  
# Line 1663 | Line 2124 | public class ConcurrentHashMapV8<K, V>
2124              Class<?> k = ConcurrentHashMapV8.class;
2125              counterOffset = UNSAFE.objectFieldOffset
2126                  (k.getDeclaredField("counter"));
2127 <            loadFactorOffset = UNSAFE.objectFieldOffset
2128 <                (k.getDeclaredField("loadFactor"));
1668 <            resizingOffset = UNSAFE.objectFieldOffset
1669 <                (k.getDeclaredField("resizing"));
2127 >            sizeCtlOffset = UNSAFE.objectFieldOffset
2128 >                (k.getDeclaredField("sizeCtl"));
2129              Class<?> sc = Node[].class;
2130              ABASE = UNSAFE.arrayBaseOffset(sc);
2131              ss = UNSAFE.arrayIndexScale(sc);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines