ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/ConcurrentHashMapV8.java
Revision: 1.1
Committed: Sun Aug 28 19:08:07 2011 UTC (12 years, 8 months ago) by dl
Branch: MAIN
Log Message:
Initial commit of CHM replacement

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 package jsr166e;
8 import jsr166e.LongAdder;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.Collection;
12 import java.util.AbstractMap;
13 import java.util.AbstractSet;
14 import java.util.AbstractCollection;
15 import java.util.Hashtable;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.Enumeration;
19 import java.util.ConcurrentModificationException;
20 import java.util.NoSuchElementException;
21 import java.util.concurrent.ConcurrentMap;
22 import java.io.Serializable;
23
24 /**
25 * A hash table supporting full concurrency of retrievals and
26 * high expected concurrency for updates. This class obeys the
27 * same functional specification as {@link java.util.Hashtable}, and
28 * includes versions of methods corresponding to each method of
29 * {@code Hashtable}. However, even though all operations are
30 * thread-safe, retrieval operations do <em>not</em> entail locking,
31 * and there is <em>not</em> any support for locking the entire table
32 * in a way that prevents all access. This class is fully
33 * interoperable with {@code Hashtable} in programs that rely on its
34 * thread safety but not on its synchronization details.
35 *
36 * <p> Retrieval operations (including {@code get}) generally do not
37 * block, so may overlap with update operations (including {@code put}
38 * and {@code remove}). Retrievals reflect the results of the most
39 * recently <em>completed</em> update operations holding upon their
40 * onset. For aggregate operations such as {@code putAll} and {@code
41 * clear}, concurrent retrievals may reflect insertion or removal of
42 * only some entries. Similarly, Iterators and Enumerations return
43 * elements reflecting the state of the hash table at some point at or
44 * since the creation of the iterator/enumeration. They do
45 * <em>not</em> throw {@link ConcurrentModificationException}.
46 * However, iterators are designed to be used by only one thread at a
47 * time. Bear in mind that the results of aggregate status methods
48 * including {@code size}, {@code isEmpty}, and {@code containsValue}
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.
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 * compatability with previous versions of this class, constructors
58 * may optionally specify an expected {@code concurrencyLevel} as an
59 * additional hint for internal sizing.
60 *
61 * <p>This class and its views and iterators implement all of the
62 * <em>optional</em> methods of the {@link Map} and {@link Iterator}
63 * interfaces.
64 *
65 * <p> Like {@link Hashtable} but unlike {@link HashMap}, this class
66 * does <em>not</em> allow {@code null} to be used as a key or value.
67 *
68 * <p>This class is a member of the
69 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
70 * Java Collections Framework</a>.
71 *
72 * <p><em>jsr166e note: This class is a candidate replacement for
73 * java.util.concurrent.ConcurrentHashMap.<em>
74 *
75 * @since 1.5
76 * @author Doug Lea
77 * @param <K> the type of keys maintained by this map
78 * @param <V> the type of mapped values
79 */
80 public class ConcurrentHashMapV8<K, V>
81 implements ConcurrentMap<K, V>, Serializable {
82 private static final long serialVersionUID = 7249069246763182397L;
83
84 /**
85 * A function computing a mapping from the given key to a value,
86 * or <code>null</code> if there is no mapping. This is a
87 * place-holder for an upcoming JDK8 interface.
88 */
89 public static interface MappingFunction<K, V> {
90 /**
91 * Returns a value for the given key, or null if there is no
92 * mapping. If this function throws an (unchecked) exception,
93 * the exception is rethrown to its caller, and no mapping is
94 * recorded. Because this function is invoked within
95 * atomicity control, the computation should be short and
96 * simple. The most common usage is to construct a new object
97 * serving as an initial mapped value.
98 *
99 * @param key the (non-null) key
100 * @return a value, or null if none
101 */
102 V map(K key);
103 }
104
105 /*
106 * Overview:
107 *
108 * The primary design goal of this hash table is to maintain
109 * concurrent readability (typically method get(), but also
110 * iterators and related methods) while minimizing update
111 * contention.
112 *
113 * Each key-value mapping is held in a Node. Because Node fields
114 * can contain special values, they are defined using plain Object
115 * types. Similarly in turn, all internal methods that use them
116 * work off Object types. All public generic-typed methods relay
117 * in/out of these internal methods, supplying casts as needed.
118 *
119 * The table is lazily initialized to a power-of-two size upon the
120 * first insertion. Each bin in the table contains a (typically
121 * short) list of Nodes. Table accesses require volatile/atomic
122 * reads, writes, and CASes. Because there is no other way to
123 * arrange this without adding further indirections, we use
124 * intrinsics (sun.misc.Unsafe) operations. The lists of nodes
125 * within bins are always accurately traversable under volatile
126 * reads, so long as lookups check hash code and non-nullness of
127 * key and value before checking key equality. (All valid hash
128 * codes are nonnegative. Negative values are served for special
129 * nodes.)
130 *
131 * A bin may be locked during update (insert, delete, and replace)
132 * operations. We do not want to waste the space required to
133 * associate a distinct lock object with each bin, so instead use
134 * the first node of a bin list itself as a lock, using builtin
135 * "synchronized" locks. These save space and we can live with
136 * only plain block-structured lock/unlock operations. Using the
137 * first node of a list as a lock does not by itself suffice
138 * though: When a node is locked, any update must first validate
139 * that it is still the first node, and retry if not. (Because new
140 * nodes are always appended to lists, once a node is first in a
141 * bin, it remains first until deleted or the bin becomes
142 * invalidated.) However, update operations can and usually do
143 * still traverse the bin until the point of update, which helps
144 * reduce cache misses on retries. This is a converse of sorts to
145 * the lazy locking technique described by Herlihy & Shavit. If
146 * there is no existing node during a put operation, then one can
147 * be CAS'ed in (without need for lock except in computeIfAbsent);
148 * the CAS serves as validation. This is on average the most
149 * common case for put operations. The expected number of locks
150 * covering different elements (i.e., bins with 2 or more nodes)
151 * is approximately 10% at steady state under default settings.
152 * Lock contention probability for two threads accessing arbitrary
153 * distinct elements is thus less than 1% even for small tables.
154 *
155 * The table is resized when occupancy exceeds a threshold. Only
156 * a single thread performs the resize (using field "resizing", to
157 * arrange exclusion), but the table otherwise remains usable for
158 * both reads and updates. Resizing proceeds by transferring bins,
159 * one by one, from the table to the next table. Upon transfer,
160 * the old table bin contains only a special forwarding node (with
161 * negative hash code ("MOVED")) that contains the next table as
162 * its key. On encountering a forwarding node, access and update
163 * operations restart, using the new table. To ensure concurrent
164 * readability of traversals, transfers must proceed from the last
165 * bin (table.length - 1) up towards the first. Any traversal
166 * starting from the first bin can then arrange to move to the new
167 * table for the rest of the traversal without revisiting nodes.
168 * This constrains bin transfers to a particular order, and so can
169 * block indefinitely waiting for the next lock, and other threads
170 * cannot help with the transfer. However, expected stalls are
171 * infrequent enough to not warrant the additional overhead and
172 * complexity of access and iteration schemes that could admit
173 * out-of-order or concurrent bin transfers.
174 *
175 * (While not yet implemented, a similar traversal scheme can
176 * apply to partial traversals during partitioned aggregate
177 * operations. Also, read-only operations give up if ever
178 * forwarded to a null table, which provides support for
179 * shutdown-style clearing, which is also not currently
180 * implemented.)
181 *
182 * The element count is maintained using a LongAdder, which avoids
183 * contention on updates but can encounter cache thrashing if read
184 * too frequently during concurrent updates. To avoid reading so
185 * often, resizing is attempted only upon adding to a bin already
186 * holding two or more nodes. Under the default threshold (0.75),
187 * and uniform hash distributions, the probability of this
188 * occurring at threshold is around 13%, meaning that only about 1
189 * in 8 puts check threshold (and after resizing, many fewer do
190 * so). To increase the probablity that a resize occurs soon
191 * enough, we offset the threshold (see THRESHOLD_OFFSET) by the
192 * expected number of puts between checks. This is currently set
193 * to 8, in accord with the default load factor. In practice, this
194 * is rarely overridden, and in any case is close enough to other
195 * plausible values not to waste dynamic probablity computation
196 * for more precision.
197 */
198
199 /* ---------------- Constants -------------- */
200
201 /**
202 * The smallest allowed table capacity. Must be a power of 2, at
203 * least 2.
204 */
205 static final int MINIMUM_CAPACITY = 2;
206
207 /**
208 * The largest allowed table capacity. Must be a power of 2, at
209 * most 1<<30.
210 */
211 static final int MAXIMUM_CAPACITY = 1 << 30;
212
213 /**
214 * The default initial table capacity. Must be a power of 2, at
215 * least MINIMUM_CAPACITY and at most MAXIMUM_CAPACITY
216 */
217 static final int DEFAULT_CAPACITY = 16;
218
219 /**
220 * The default load factor for this table, used when not otherwise
221 * specified in a constructor.
222 */
223 static final float DEFAULT_LOAD_FACTOR = 0.75f;
224
225 /**
226 * The default concurrency level for this table. Unused, but
227 * defined for compatibility with previous versions of this class.
228 */
229 static final int DEFAULT_CONCURRENCY_LEVEL = 16;
230
231 /**
232 * The count value to offset thesholds to compensate for checking
233 * for resizing only when inserting into bins with two or more
234 * elements. See above for explanation.
235 */
236 static final int THRESHOLD_OFFSET = 8;
237
238 /**
239 * Special node hash value indicating to use table in node.key
240 * Must be negative.
241 */
242 static final int MOVED = -1;
243
244 /* ---------------- Fields -------------- */
245
246 /**
247 * The array of bins. Lazily initialized upon first insertion.
248 * Size is always a power of two. Accessed directly by inner
249 * classes.
250 */
251 transient volatile Node[] table;
252
253 /** The counter maintaining number of elements. */
254 private transient final LongAdder counter;
255 /** Nonzero when table is being initialized or resized. Updated via CAS. */
256 private transient volatile int resizing;
257 /** The target load factor for the table. */
258 private transient float loadFactor;
259 /** The next element count value upon which to resize the table. */
260 private transient int threshold;
261 /** The initial capacity of the table. */
262 private transient int initCap;
263
264 // views
265 transient Set<K> keySet;
266 transient Set<Map.Entry<K,V>> entrySet;
267 transient Collection<V> values;
268
269 /** For serialization compatability. Null unless serialized; see below */
270 Segment<K,V>[] segments;
271
272 /**
273 * Applies a supplemental hash function to a given hashCode, which
274 * defends against poor quality hash functions. The result must
275 * be non-negative, and for reasonable performance must have good
276 * avalanche properties; i.e., that each bit of the argument
277 * affects each bit (except sign bit) of the result.
278 */
279 private static final int spread(int h) {
280 // Apply base step of MurmurHash; see http://code.google.com/p/smhasher/
281 h ^= h >>> 16;
282 h *= 0x85ebca6b;
283 h ^= h >>> 13;
284 h *= 0xc2b2ae35;
285 return (h >>> 16) ^ (h & 0x7fffffff); // mask out sign bit
286 }
287
288 /**
289 * Key-value entry. Note that this is never exported out as a
290 * user-visible Map.Entry.
291 */
292 static final class Node {
293 final int hash;
294 final Object key;
295 volatile Object val;
296 volatile Node next;
297
298 Node(int hash, Object key, Object val, Node next) {
299 this.hash = hash;
300 this.key = key;
301 this.val = val;
302 this.next = next;
303 }
304 }
305
306 /*
307 * Volatile access nethods are used for table elements as well as
308 * elements of in-progress next table while resizing. Uses in
309 * access and update methods are null checked by callers, and
310 * implicitly bounds-checked, relying on the invariants that tab
311 * arrays have non-zero size, and all indices are masked with
312 * (tab.length - 1) which is never negative and always less than
313 * length. The only other usage is in HashIterator.advance, which
314 * performs explicit checks.
315 */
316
317 static final Node tabAt(Node[] tab, int i) { // used in HashIterator
318 return (Node)UNSAFE.getObjectVolatile(tab, ((long)i<<ASHIFT)+ABASE);
319 }
320
321 private static final boolean casTabAt(Node[] tab, int i, Node c, Node v) {
322 return UNSAFE.compareAndSwapObject(tab, ((long)i<<ASHIFT)+ABASE, c, v);
323 }
324
325 private static final void setTabAt(Node[] tab, int i, Node v) {
326 UNSAFE.putObjectVolatile(tab, ((long)i<<ASHIFT)+ABASE, v);
327 }
328
329 /* ---------------- Access and update operations -------------- */
330
331 /** Implements get and containsKey **/
332 private final Object internalGet(Object k) {
333 int h = spread(k.hashCode());
334 Node[] tab = table;
335 retry: while (tab != null) {
336 Node e = tabAt(tab, (tab.length - 1) & h);
337 while (e != null) {
338 int eh = e.hash;
339 if (eh == h) {
340 Object ek = e.key, ev = e.val;
341 if (ev != null && ek != null && (k == ek || k.equals(ek)))
342 return ev;
343 }
344 if (eh < 0) { // bin was moved during resize
345 tab = (Node[])e.key;
346 continue retry;
347 }
348 e = e.next;
349 }
350 break;
351 }
352 return null;
353 }
354
355 /** Implements put and putIfAbsent **/
356 private final Object internalPut(Object k, Object v, boolean replace) {
357 int h = spread(k.hashCode());
358 Object oldVal = null; // the previous value or null if none
359 Node node = null; // the node created if absent
360 Node[] tab = table;
361 for (;;) {
362 Node e; int i;
363 if (tab == null)
364 tab = grow(0);
365 else if ((e = tabAt(tab, i = (tab.length - 1) & h)) == null) {
366 if (node == null)
367 node = new Node(h, k, v, null);
368 if (casTabAt(tab, i, null, node))
369 break;
370 }
371 else if (e.hash < 0)
372 tab = (Node[])e.key;
373 else {
374 boolean validated = false;
375 boolean checkSize = false;
376 synchronized(e) {
377 Node first = e;
378 for (;;) {
379 Object ek, ev;
380 if ((ev = e.val) == null)
381 break;
382 if (e.hash == h && (ek = e.key) != null &&
383 (k == ek || k.equals(ek))) {
384 if (tabAt(tab, i) == first) {
385 validated = true;
386 oldVal = ev;
387 if (replace)
388 e.val = v;
389 }
390 break;
391 }
392 Node last = e;
393 if ((e = e.next) == null) {
394 if (tabAt(tab, i) == first) {
395 validated = true;
396 if (node == null)
397 node = new Node(h, k, v, null);
398 last.next = node;
399 if (last != first)
400 checkSize = true;
401 }
402 break;
403 }
404 }
405 }
406 if (validated) {
407 if (checkSize && tab.length < MAXIMUM_CAPACITY &&
408 resizing == 0 && counter.sum() >= threshold)
409 grow(0);
410 break;
411 }
412 }
413 }
414 if (oldVal == null)
415 counter.increment();
416 return oldVal;
417 }
418
419 /**
420 * Covers the four public remove/replace methods: Replaces node
421 * value with v, conditional upon match of cv if non-null. If
422 * resulting value is null, delete.
423 */
424 private final Object internalReplace(Object k, Object v, Object cv) {
425 int h = spread(k.hashCode());
426 Object oldVal = null;
427 Node e; int i;
428 Node[] tab = table;
429 while (tab != null &&
430 (e = tabAt(tab, i = (tab.length - 1) & h)) != null) {
431 if (e.hash < 0)
432 tab = (Node[])e.key;
433 else {
434 boolean validated = false;
435 boolean deleted = false;
436 synchronized(e) {
437 Node pred = null;
438 Node first = e;
439 for (;;) {
440 Object ek, ev;
441 if ((ev = e.val) == null)
442 break;
443 if (e.hash == h && (ek = e.key) != null &&
444 (k == ek || k.equals(ek))) {
445 if (tabAt(tab, i) == first) {
446 validated = true;
447 if (cv == null || cv == ev || cv.equals(ev)) {
448 oldVal = ev;
449 if ((e.val = v) == null) {
450 deleted = true;
451 Node en = e.next;
452 if (pred != null)
453 pred.next = en;
454 else
455 setTabAt(tab, i, en);
456 }
457 }
458 }
459 break;
460 }
461 pred = e;
462 if ((e = e.next) == null) {
463 if (tabAt(tab, i) == first)
464 validated = true;
465 break;
466 }
467 }
468 }
469 if (validated) {
470 if (deleted)
471 counter.decrement();
472 break;
473 }
474 }
475 }
476 return oldVal;
477 }
478
479 /** Implements computeIfAbsent */
480 @SuppressWarnings("unchecked")
481 private final V computeVal(K k, MappingFunction<? super K, ? extends V> f) {
482 int h = spread(k.hashCode());
483 V val = null;
484 Node node = null;
485 boolean added = false;
486 boolean validated = false;
487 Node[] tab = table;
488 do {
489 Node e; int i;
490 if (tab == null)
491 tab = grow(0);
492 else if ((e = tabAt(tab, i = (tab.length - 1) & h)) == null) {
493 if (node == null)
494 node = new Node(h, k, null, null);
495 synchronized(node) {
496 if (casTabAt(tab, i, null, node)) {
497 validated = true;
498 try {
499 val = f.map(k);
500 if (val != null) {
501 node.val = val;
502 added = true;
503 }
504 } finally {
505 if (!added)
506 setTabAt(tab, i, null);
507 }
508 }
509 }
510 }
511 else if (e.hash < 0)
512 tab = (Node[])e.key;
513 else {
514 boolean checkSize = false;
515 synchronized(e) {
516 Node first = e;
517 for (;;) {
518 Object ek, ev;
519 if ((ev = e.val) == null)
520 break;
521 if (e.hash == h && (ek = e.key) != null &&
522 (k == ek || k.equals(ek))) {
523 if (tabAt(tab, i) == first) {
524 validated = true;
525 val = (V)ev;
526 }
527 break;
528 }
529 Node last = e;
530 if ((e = e.next) == null) {
531 if (tabAt(tab, i) == first) {
532 validated = true;
533 if ((val = f.map(k)) != null) {
534 if (node == null)
535 node = new Node(h, k, val, null);
536 else
537 node.val = val;
538 last.next = node;
539 if (last != first)
540 checkSize = true;
541 added = true;
542 }
543 }
544 break;
545 }
546 }
547 }
548 if (checkSize && tab.length < MAXIMUM_CAPACITY &&
549 resizing == 0 && counter.sum() >= threshold)
550 grow(0);
551 }
552 } while (!validated);
553 if (added)
554 counter.increment();
555 return val;
556 }
557
558 /*
559 * Reclassifies nodes in each bin to new table. Because we are
560 * using power-of-two expansion, the elements from each bin must
561 * either stay at same index, or move with a power of two
562 * offset. We eliminate unnecessary node creation by catching
563 * cases where old nodes can be reused because their next fields
564 * won't change. Statistically, at the default threshold, only
565 * about one-sixth of them need cloning when a table doubles. The
566 * nodes they replace will be garbage collectable as soon as they
567 * are no longer referenced by any reader thread that may be in
568 * the midst of concurrently traversing table.
569 *
570 * Transfers are done from the bottom up to preserve iterator
571 * traversability. On each step, the old bin is locked,
572 * moved/copied, and then replaced with a forwarding node.
573 */
574 private static final void transfer(Node[] tab, Node[] nextTab) {
575 int n = tab.length;
576 int mask = nextTab.length - 1;
577 Node fwd = new Node(MOVED, nextTab, null, null);
578 for (int i = n - 1; i >= 0; --i) {
579 for (Node e;;) {
580 if ((e = tabAt(tab, i)) == null) {
581 if (casTabAt(tab, i, e, fwd))
582 break;
583 }
584 else {
585 boolean validated = false;
586 synchronized(e) {
587 int idx = e.hash & mask;
588 Node lastRun = e;
589 for (Node p = e.next; p != null; p = p.next) {
590 int j = p.hash & mask;
591 if (j != idx) {
592 idx = j;
593 lastRun = p;
594 }
595 }
596 if (tabAt(tab, i) == e) {
597 validated = true;
598 setTabAt(nextTab, idx, lastRun);
599 for (Node p = e; p != lastRun; p = p.next) {
600 int h = p.hash;
601 int j = h & mask;
602 Object pk = p.key, pv = p.val;
603 Node r = tabAt(nextTab, j);
604 setTabAt(nextTab, j, new Node(h, pk, pv, r));
605 }
606 setTabAt(tab, i, fwd);
607 }
608 }
609 if (validated)
610 break;
611 }
612 }
613 }
614 }
615
616 /**
617 * If not already resizing, initializes or creates next table and
618 * transfers bins. Rechecks occupancy after a transfer to see if
619 * another resize is already needed because resizings are lagging
620 * additions.
621 *
622 * @param sizeHint overridden capacity target (nonzero only from putAll)
623 * @return current table
624 */
625 private final Node[] grow(int sizeHint) {
626 Node[] tab;
627 if (resizing == 0 &&
628 UNSAFE.compareAndSwapInt(this, resizingOffset, 0, 1)) {
629 try {
630 for (;;) {
631 int cap, n;
632 if ((tab = table) == null) {
633 int c = initCap;
634 if (c < sizeHint)
635 c = sizeHint;
636 if (c == DEFAULT_CAPACITY)
637 cap = c;
638 else if (c >= MAXIMUM_CAPACITY)
639 cap = MAXIMUM_CAPACITY;
640 else {
641 cap = MINIMUM_CAPACITY;
642 while (cap < c)
643 cap <<= 1;
644 }
645 }
646 else if ((n = tab.length) < MAXIMUM_CAPACITY &&
647 (sizeHint <= 0 || n < sizeHint))
648 cap = n << 1;
649 else
650 break;
651 threshold = (int)(cap * loadFactor) - THRESHOLD_OFFSET;
652 Node[] nextTab = new Node[cap];
653 if (tab != null)
654 transfer(tab, nextTab);
655 table = nextTab;
656 if (tab == null || counter.sum() < threshold) {
657 tab = nextTab;
658 break;
659 }
660 }
661 } finally {
662 resizing = 0;
663 }
664 }
665 else if ((tab = table) == null)
666 Thread.yield(); // lost initialization race; just spin
667 return tab;
668 }
669
670 /**
671 * Implements putAll and constructor with Map argument. Tries to
672 * first override initial capacity or grow (once) based on map
673 * size to pre-allocate table space.
674 */
675 private final void internalPutAll(Map<? extends K, ? extends V> m) {
676 int s = m.size();
677 grow((s >= (MAXIMUM_CAPACITY >>> 1))? s : s + (s >>> 1));
678 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
679 Object k = e.getKey();
680 Object v = e.getValue();
681 if (k == null || v == null)
682 throw new NullPointerException();
683 internalPut(k, v, true);
684 }
685 }
686
687 /**
688 * Implements clear. Steps through each bin, removing all nodes.
689 */
690 private final void internalClear() {
691 long delta = 0L; // negative of number of deletions
692 int i = 0;
693 Node[] tab = table;
694 while (tab != null && i < tab.length) {
695 Node e = tabAt(tab, i);
696 if (e == null)
697 ++i;
698 else if (e.hash < 0)
699 tab = (Node[])e.key;
700 else {
701 boolean validated = false;
702 synchronized(e) {
703 if (tabAt(tab, i) == e) {
704 validated = true;
705 do {
706 if (e.val != null) {
707 e.val = null;
708 --delta;
709 }
710 } while ((e = e.next) != null);
711 setTabAt(tab, i, null);
712 }
713 }
714 if (validated)
715 ++i;
716 }
717 }
718 counter.add(delta);
719 }
720
721 /**
722 * Base class for key, value, and entry iterators, plus internal
723 * implementations of public traversal-based methods, to avoid
724 * duplicating traversal code.
725 */
726 class HashIterator {
727 private Node next; // the next entry to return
728 private Node[] tab; // current table; updated if resized
729 private Node lastReturned; // the last entry returned, for remove
730 private Object nextVal; // cached value of next
731 private int index; // index of bin to use next
732 private int baseIndex; // current index of initial table
733 private final int baseSize; // initial table size
734
735 HashIterator() {
736 Node[] t = tab = table;
737 if (t == null)
738 baseSize = 0;
739 else {
740 baseSize = t.length;
741 advance(null);
742 }
743 }
744
745 public final boolean hasNext() { return next != null; }
746 public final boolean hasMoreElements() { return next != null; }
747
748 /**
749 * Advances next. Normally, iteration proceeds bin-by-bin
750 * traversing lists. However, if the table has been resized,
751 * then all future steps must traverse both the bin at the
752 * current index as well as at (index + baseSize); and so on
753 * for further resizings. To paranoically cope with potential
754 * (improper) sharing of iterators across threads, table reads
755 * are bounds-checked.
756 */
757 final void advance(Node e) {
758 for (;;) {
759 Node[] t; int i; // for bounds checks
760 if (e != null) {
761 Object ek = e.key, ev = e.val;
762 if (ev != null && ek != null) {
763 nextVal = ev;
764 next = e;
765 break;
766 }
767 e = e.next;
768 }
769 else if (baseIndex < baseSize && (t = tab) != null &&
770 t.length > (i = index) && i >= 0) {
771 if ((e = tabAt(t, i)) != null && e.hash < 0) {
772 tab = (Node[])e.key;
773 e = null;
774 }
775 else if (i + baseSize < t.length)
776 index += baseSize; // visit forwarded upper slots
777 else
778 index = ++baseIndex;
779 }
780 else {
781 next = null;
782 break;
783 }
784 }
785 }
786
787 final Object nextKey() {
788 Node e = next;
789 if (e == null)
790 throw new NoSuchElementException();
791 Object k = e.key;
792 advance((lastReturned = e).next);
793 return k;
794 }
795
796 final Object nextValue() {
797 Node e = next;
798 if (e == null)
799 throw new NoSuchElementException();
800 Object v = nextVal;
801 advance((lastReturned = e).next);
802 return v;
803 }
804
805 final WriteThroughEntry nextEntry() {
806 Node e = next;
807 if (e == null)
808 throw new NoSuchElementException();
809 WriteThroughEntry entry =
810 new WriteThroughEntry(e.key, nextVal);
811 advance((lastReturned = e).next);
812 return entry;
813 }
814
815 public final void remove() {
816 if (lastReturned == null)
817 throw new IllegalStateException();
818 ConcurrentHashMapV8.this.remove(lastReturned.key);
819 lastReturned = null;
820 }
821
822 /** Helper for serialization */
823 final void writeEntries(java.io.ObjectOutputStream s)
824 throws java.io.IOException {
825 Node e;
826 while ((e = next) != null) {
827 s.writeObject(e.key);
828 s.writeObject(nextVal);
829 advance(e.next);
830 }
831 }
832
833 /** Helper for containsValue */
834 final boolean containsVal(Object value) {
835 if (value != null) {
836 Node e;
837 while ((e = next) != null) {
838 Object v = nextVal;
839 if (value == v || value.equals(v))
840 return true;
841 advance(e.next);
842 }
843 }
844 return false;
845 }
846
847 /** Helper for Map.hashCode */
848 final int mapHashCode() {
849 int h = 0;
850 Node e;
851 while ((e = next) != null) {
852 h += e.key.hashCode() ^ nextVal.hashCode();
853 advance(e.next);
854 }
855 return h;
856 }
857
858 /** Helper for Map.toString */
859 final String mapToString() {
860 Node e = next;
861 if (e == null)
862 return "{}";
863 StringBuilder sb = new StringBuilder();
864 sb.append('{');
865 for (;;) {
866 sb.append(e.key == this ? "(this Map)" : e.key);
867 sb.append('=');
868 sb.append(nextVal == this ? "(this Map)" : nextVal);
869 advance(e.next);
870 if ((e = next) != null)
871 sb.append(',').append(' ');
872 else
873 return sb.append('}').toString();
874 }
875 }
876 }
877
878 /* ---------------- Public operations -------------- */
879
880 /**
881 * Creates a new, empty map with the specified initial
882 * capacity, load factor and concurrency level.
883 *
884 * @param initialCapacity the initial capacity. The implementation
885 * performs internal sizing to accommodate this many elements.
886 * @param loadFactor the load factor threshold, used to control resizing.
887 * Resizing may be performed when the average number of elements per
888 * bin exceeds this threshold.
889 * @param concurrencyLevel the estimated number of concurrently
890 * updating threads. The implementation may use this value as
891 * a sizing hint.
892 * @throws IllegalArgumentException if the initial capacity is
893 * negative or the load factor or concurrencyLevel are
894 * nonpositive.
895 */
896 public ConcurrentHashMapV8(int initialCapacity,
897 float loadFactor, int concurrencyLevel) {
898 if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
899 throw new IllegalArgumentException();
900 this.initCap = initialCapacity;
901 this.loadFactor = loadFactor;
902 this.counter = new LongAdder();
903 }
904
905 /**
906 * Creates a new, empty map with the specified initial capacity
907 * and load factor and with the default concurrencyLevel (16).
908 *
909 * @param initialCapacity The implementation performs internal
910 * sizing to accommodate this many elements.
911 * @param loadFactor the load factor threshold, used to control resizing.
912 * Resizing may be performed when the average number of elements per
913 * bin exceeds this threshold.
914 * @throws IllegalArgumentException if the initial capacity of
915 * elements is negative or the load factor is nonpositive
916 *
917 * @since 1.6
918 */
919 public ConcurrentHashMapV8(int initialCapacity, float loadFactor) {
920 this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
921 }
922
923 /**
924 * Creates a new, empty map with the specified initial capacity,
925 * and with default load factor (0.75) and concurrencyLevel (16).
926 *
927 * @param initialCapacity the initial capacity. The implementation
928 * performs internal sizing to accommodate this many elements.
929 * @throws IllegalArgumentException if the initial capacity of
930 * elements is negative.
931 */
932 public ConcurrentHashMapV8(int initialCapacity) {
933 this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
934 }
935
936 /**
937 * Creates a new, empty map with a default initial capacity (16),
938 * load factor (0.75) and concurrencyLevel (16).
939 */
940 public ConcurrentHashMapV8() {
941 this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
942 }
943
944 /**
945 * Creates a new map with the same mappings as the given map.
946 * The map is created with a capacity of 1.5 times the number
947 * of mappings in the given map or 16 (whichever is greater),
948 * and a default load factor (0.75) and concurrencyLevel (16).
949 *
950 * @param m the map
951 */
952 public ConcurrentHashMapV8(Map<? extends K, ? extends V> m) {
953 this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
954 if (m == null)
955 throw new NullPointerException();
956 internalPutAll(m);
957 }
958
959 /**
960 * Returns {@code true} if this map contains no key-value mappings.
961 *
962 * @return {@code true} if this map contains no key-value mappings
963 */
964 public boolean isEmpty() {
965 return counter.sum() == 0L;
966 }
967
968 /**
969 * Returns the number of key-value mappings in this map. If the
970 * map contains more than {@code Integer.MAX_VALUE} elements, returns
971 * {@code Integer.MAX_VALUE}.
972 *
973 * @return the number of key-value mappings in this map
974 */
975 public int size() {
976 long n = counter.sum();
977 return n >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)n;
978 }
979
980 /**
981 * Returns the value to which the specified key is mapped,
982 * or {@code null} if this map contains no mapping for the key.
983 *
984 * <p>More formally, if this map contains a mapping from a key
985 * {@code k} to a value {@code v} such that {@code key.equals(k)},
986 * then this method returns {@code v}; otherwise it returns
987 * {@code null}. (There can be at most one such mapping.)
988 *
989 * @throws NullPointerException if the specified key is null
990 */
991 @SuppressWarnings("unchecked")
992 public V get(Object key) {
993 if (key == null)
994 throw new NullPointerException();
995 return (V)internalGet(key);
996 }
997
998 /**
999 * Tests if the specified object is a key in this table.
1000 *
1001 * @param key possible key
1002 * @return {@code true} if and only if the specified object
1003 * is a key in this table, as determined by the
1004 * {@code equals} method; {@code false} otherwise.
1005 * @throws NullPointerException if the specified key is null
1006 */
1007 public boolean containsKey(Object key) {
1008 if (key == null)
1009 throw new NullPointerException();
1010 return internalGet(key) != null;
1011 }
1012
1013 /**
1014 * Returns {@code true} if this map maps one or more keys to the
1015 * specified value. Note: This method requires a full internal
1016 * traversal of the hash table, and so is much slower than
1017 * method {@code containsKey}.
1018 *
1019 * @param value value whose presence in this map is to be tested
1020 * @return {@code true} if this map maps one or more keys to the
1021 * specified value
1022 * @throws NullPointerException if the specified value is null
1023 */
1024 public boolean containsValue(Object value) {
1025 if (value == null)
1026 throw new NullPointerException();
1027 return new HashIterator().containsVal(value);
1028 }
1029
1030 /**
1031 * Legacy method testing if some key maps into the specified value
1032 * in this table. This method is identical in functionality to
1033 * {@link #containsValue}, and exists solely to ensure
1034 * full compatibility with class {@link java.util.Hashtable},
1035 * which supported this method prior to introduction of the
1036 * Java Collections framework.
1037 *
1038 * @param value a value to search for
1039 * @return {@code true} if and only if some key maps to the
1040 * {@code value} argument in this table as
1041 * determined by the {@code equals} method;
1042 * {@code false} otherwise
1043 * @throws NullPointerException if the specified value is null
1044 */
1045 public boolean contains(Object value) {
1046 return containsValue(value);
1047 }
1048
1049 /**
1050 * Maps the specified key to the specified value in this table.
1051 * Neither the key nor the value can be null.
1052 *
1053 * <p> The value can be retrieved by calling the {@code get} method
1054 * with a key that is equal to the original key.
1055 *
1056 * @param key key with which the specified value is to be associated
1057 * @param value value to be associated with the specified key
1058 * @return the previous value associated with {@code key}, or
1059 * {@code null} if there was no mapping for {@code key}
1060 * @throws NullPointerException if the specified key or value is null
1061 */
1062 @SuppressWarnings("unchecked")
1063 public V put(K key, V value) {
1064 if (key == null || value == null)
1065 throw new NullPointerException();
1066 return (V)internalPut(key, value, true);
1067 }
1068
1069 /**
1070 * {@inheritDoc}
1071 *
1072 * @return the previous value associated with the specified key,
1073 * or {@code null} if there was no mapping for the key
1074 * @throws NullPointerException if the specified key or value is null
1075 */
1076 @SuppressWarnings("unchecked")
1077 public V putIfAbsent(K key, V value) {
1078 if (key == null || value == null)
1079 throw new NullPointerException();
1080 return (V)internalPut(key, value, false);
1081 }
1082
1083 /**
1084 * Copies all of the mappings from the specified map to this one.
1085 * These mappings replace any mappings that this map had for any of the
1086 * keys currently in the specified map.
1087 *
1088 * @param m mappings to be stored in this map
1089 */
1090 public void putAll(Map<? extends K, ? extends V> m) {
1091 if (m == null)
1092 throw new NullPointerException();
1093 internalPutAll(m);
1094 }
1095
1096 /**
1097 * If the specified key is not already associated with a value,
1098 * computes its value using the given mappingFunction, and if
1099 * non-null, enters it into the map. This is equivalent to
1100 *
1101 * <pre>
1102 * if (map.containsKey(key))
1103 * return map.get(key);
1104 * value = mappingFunction.map(key);
1105 * if (value != null)
1106 * return map.put(key, value);
1107 * else
1108 * return null;
1109 * </pre>
1110 *
1111 * except that the action is performed atomically. Some attempted
1112 * operations on this map by other threads may be blocked while
1113 * computation is in progress. Because this function is invoked
1114 * within atomicity control, the computation should be short and
1115 * simple, and must not attempt to update any other mappings of
1116 * this Map. The most common usage is to construct a new object
1117 * serving as an initial mapped value, or memoized result.
1118 *
1119 * @param key key with which the specified value is to be associated
1120 * @param mappingFunction the function to compute a value
1121 * @return the current (existing or computed) value associated with
1122 * the specified key, or {@code null} if the computation
1123 * returned {@code null}.
1124 * @throws NullPointerException if the specified key or mappingFunction
1125 * is null,
1126 * @throws RuntimeException or Error if the mappingFunction does so,
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)
1131 throw new NullPointerException();
1132 return computeVal(key, mappingFunction);
1133 }
1134
1135 /**
1136 * Removes the key (and its corresponding value) from this map.
1137 * This method does nothing if the key is not in the map.
1138 *
1139 * @param key the key that needs to be removed
1140 * @return the previous value associated with {@code key}, or
1141 * {@code null} if there was no mapping for {@code key}
1142 * @throws NullPointerException if the specified key is null
1143 */
1144 @SuppressWarnings("unchecked")
1145 public V remove(Object key) {
1146 if (key == null)
1147 throw new NullPointerException();
1148 return (V)internalReplace(key, null, null);
1149 }
1150
1151 /**
1152 * {@inheritDoc}
1153 *
1154 * @throws NullPointerException if the specified key is null
1155 */
1156 public boolean remove(Object key, Object value) {
1157 if (key == null)
1158 throw new NullPointerException();
1159 if (value == null)
1160 return false;
1161 return internalReplace(key, null, value) != null;
1162 }
1163
1164 /**
1165 * {@inheritDoc}
1166 *
1167 * @throws NullPointerException if any of the arguments are null
1168 */
1169 public boolean replace(K key, V oldValue, V newValue) {
1170 if (key == null || oldValue == null || newValue == null)
1171 throw new NullPointerException();
1172 return internalReplace(key, newValue, oldValue) != null;
1173 }
1174
1175 /**
1176 * {@inheritDoc}
1177 *
1178 * @return the previous value associated with the specified key,
1179 * or {@code null} if there was no mapping for the key
1180 * @throws NullPointerException if the specified key or value is null
1181 */
1182 @SuppressWarnings("unchecked")
1183 public V replace(K key, V value) {
1184 if (key == null || value == null)
1185 throw new NullPointerException();
1186 return (V)internalReplace(key, value, null);
1187 }
1188
1189 /**
1190 * Removes all of the mappings from this map.
1191 */
1192 public void clear() {
1193 internalClear();
1194 }
1195
1196 /**
1197 * Returns a {@link Set} view of the keys contained in this map.
1198 * The set is backed by the map, so changes to the map are
1199 * reflected in the set, and vice-versa. The set supports element
1200 * removal, which removes the corresponding mapping from this map,
1201 * via the {@code Iterator.remove}, {@code Set.remove},
1202 * {@code removeAll}, {@code retainAll}, and {@code clear}
1203 * operations. It does not support the {@code add} or
1204 * {@code addAll} operations.
1205 *
1206 * <p>The view's {@code iterator} is a "weakly consistent" iterator
1207 * that will never throw {@link ConcurrentModificationException},
1208 * and guarantees to traverse elements as they existed upon
1209 * construction of the iterator, and may (but is not guaranteed to)
1210 * reflect any modifications subsequent to construction.
1211 */
1212 public Set<K> keySet() {
1213 Set<K> ks = keySet;
1214 return (ks != null) ? ks : (keySet = new KeySet());
1215 }
1216
1217 /**
1218 * Returns a {@link Collection} view of the values contained in this map.
1219 * The collection is backed by the map, so changes to the map are
1220 * reflected in the collection, and vice-versa. The collection
1221 * supports element removal, which removes the corresponding
1222 * mapping from this map, via the {@code Iterator.remove},
1223 * {@code Collection.remove}, {@code removeAll},
1224 * {@code retainAll}, and {@code clear} operations. It does not
1225 * support the {@code add} or {@code addAll} operations.
1226 *
1227 * <p>The view's {@code iterator} is a "weakly consistent" iterator
1228 * that will never throw {@link ConcurrentModificationException},
1229 * and guarantees to traverse elements as they existed upon
1230 * construction of the iterator, and may (but is not guaranteed to)
1231 * reflect any modifications subsequent to construction.
1232 */
1233 public Collection<V> values() {
1234 Collection<V> vs = values;
1235 return (vs != null) ? vs : (values = new Values());
1236 }
1237
1238 /**
1239 * Returns a {@link Set} view of the mappings contained in this map.
1240 * The set is backed by the map, so changes to the map are
1241 * reflected in the set, and vice-versa. The set supports element
1242 * removal, which removes the corresponding mapping from the map,
1243 * via the {@code Iterator.remove}, {@code Set.remove},
1244 * {@code removeAll}, {@code retainAll}, and {@code clear}
1245 * operations. It does not support the {@code add} or
1246 * {@code addAll} operations.
1247 *
1248 * <p>The view's {@code iterator} is a "weakly consistent" iterator
1249 * that will never throw {@link ConcurrentModificationException},
1250 * and guarantees to traverse elements as they existed upon
1251 * construction of the iterator, and may (but is not guaranteed to)
1252 * reflect any modifications subsequent to construction.
1253 */
1254 public Set<Map.Entry<K,V>> entrySet() {
1255 Set<Map.Entry<K,V>> es = entrySet;
1256 return (es != null) ? es : (entrySet = new EntrySet());
1257 }
1258
1259 /**
1260 * Returns an enumeration of the keys in this table.
1261 *
1262 * @return an enumeration of the keys in this table
1263 * @see #keySet()
1264 */
1265 public Enumeration<K> keys() {
1266 return new KeyIterator();
1267 }
1268
1269 /**
1270 * Returns an enumeration of the values in this table.
1271 *
1272 * @return an enumeration of the values in this table
1273 * @see #values()
1274 */
1275 public Enumeration<V> elements() {
1276 return new ValueIterator();
1277 }
1278
1279 /**
1280 * {@inheritDoc}
1281 */
1282 public int hashCode() {
1283 return new HashIterator().mapHashCode();
1284 }
1285
1286 /**
1287 * {@inheritDoc}
1288 */
1289 public String toString() {
1290 return new HashIterator().mapToString();
1291 }
1292
1293 /**
1294 * {@inheritDoc}
1295 */
1296 public boolean equals(Object o) {
1297 if (o == this)
1298 return true;
1299 if (!(o instanceof Map))
1300 return false;
1301 Map<?,?> m = (Map<?,?>) o;
1302 try {
1303 for (Map.Entry<K,V> e : this.entrySet())
1304 if (! e.getValue().equals(m.get(e.getKey())))
1305 return false;
1306 for (Map.Entry<?,?> e : m.entrySet()) {
1307 Object k = e.getKey();
1308 Object v = e.getValue();
1309 if (k == null || v == null || !v.equals(get(k)))
1310 return false;
1311 }
1312 return true;
1313 } catch (ClassCastException unused) {
1314 return false;
1315 } catch (NullPointerException unused) {
1316 return false;
1317 }
1318 }
1319
1320 /**
1321 * Custom Entry class used by EntryIterator.next(), that relays
1322 * setValue changes to the underlying map.
1323 */
1324 final class WriteThroughEntry extends AbstractMap.SimpleEntry<K,V> {
1325 @SuppressWarnings("unchecked")
1326 WriteThroughEntry(Object k, Object v) {
1327 super((K)k, (V)v);
1328 }
1329
1330 /**
1331 * Sets our entry's value and writes through to the map. The
1332 * value to return is somewhat arbitrary here. Since a
1333 * WriteThroughEntry does not necessarily track asynchronous
1334 * changes, the most recent "previous" value could be
1335 * different from what we return (or could even have been
1336 * removed in which case the put will re-establish). We do not
1337 * and cannot guarantee more.
1338 */
1339 public V setValue(V value) {
1340 if (value == null) throw new NullPointerException();
1341 V v = super.setValue(value);
1342 ConcurrentHashMapV8.this.put(getKey(), value);
1343 return v;
1344 }
1345 }
1346
1347 final class KeyIterator extends HashIterator
1348 implements Iterator<K>, Enumeration<K> {
1349 @SuppressWarnings("unchecked")
1350 public final K next() { return (K)super.nextKey(); }
1351 @SuppressWarnings("unchecked")
1352 public final K nextElement() { return (K)super.nextKey(); }
1353 }
1354
1355 final class ValueIterator extends HashIterator
1356 implements Iterator<V>, Enumeration<V> {
1357 @SuppressWarnings("unchecked")
1358 public final V next() { return (V)super.nextValue(); }
1359 @SuppressWarnings("unchecked")
1360 public final V nextElement() { return (V)super.nextValue(); }
1361 }
1362
1363 final class EntryIterator extends HashIterator
1364 implements Iterator<Entry<K,V>> {
1365 public final Map.Entry<K,V> next() { return super.nextEntry(); }
1366 }
1367
1368 final class KeySet extends AbstractSet<K> {
1369 public int size() {
1370 return ConcurrentHashMapV8.this.size();
1371 }
1372 public boolean isEmpty() {
1373 return ConcurrentHashMapV8.this.isEmpty();
1374 }
1375 public void clear() {
1376 ConcurrentHashMapV8.this.clear();
1377 }
1378 public Iterator<K> iterator() {
1379 return new KeyIterator();
1380 }
1381 public boolean contains(Object o) {
1382 return ConcurrentHashMapV8.this.containsKey(o);
1383 }
1384 public boolean remove(Object o) {
1385 return ConcurrentHashMapV8.this.remove(o) != null;
1386 }
1387 }
1388
1389 final class Values extends AbstractCollection<V> {
1390 public int size() {
1391 return ConcurrentHashMapV8.this.size();
1392 }
1393 public boolean isEmpty() {
1394 return ConcurrentHashMapV8.this.isEmpty();
1395 }
1396 public void clear() {
1397 ConcurrentHashMapV8.this.clear();
1398 }
1399 public Iterator<V> iterator() {
1400 return new ValueIterator();
1401 }
1402 public boolean contains(Object o) {
1403 return ConcurrentHashMapV8.this.containsValue(o);
1404 }
1405 }
1406
1407 final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1408 public int size() {
1409 return ConcurrentHashMapV8.this.size();
1410 }
1411 public boolean isEmpty() {
1412 return ConcurrentHashMapV8.this.isEmpty();
1413 }
1414 public void clear() {
1415 ConcurrentHashMapV8.this.clear();
1416 }
1417 public Iterator<Map.Entry<K,V>> iterator() {
1418 return new EntryIterator();
1419 }
1420 public boolean contains(Object o) {
1421 if (!(o instanceof Map.Entry))
1422 return false;
1423 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1424 V v = ConcurrentHashMapV8.this.get(e.getKey());
1425 return v != null && v.equals(e.getValue());
1426 }
1427 public boolean remove(Object o) {
1428 if (!(o instanceof Map.Entry))
1429 return false;
1430 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1431 return ConcurrentHashMapV8.this.remove(e.getKey(), e.getValue());
1432 }
1433 }
1434
1435 /* ---------------- Serialization Support -------------- */
1436
1437 /**
1438 * Helper class used in previous version, declared for the sake of
1439 * serialization compatibility
1440 */
1441 static class Segment<K,V> extends java.util.concurrent.locks.ReentrantLock
1442 implements Serializable {
1443 private static final long serialVersionUID = 2249069246763182397L;
1444 final float loadFactor;
1445 Segment(float lf) { this.loadFactor = lf; }
1446 }
1447
1448 /**
1449 * Saves the state of the {@code ConcurrentHashMapV8} instance to a
1450 * stream (i.e., serializes it).
1451 * @param s the stream
1452 * @serialData
1453 * the key (Object) and value (Object)
1454 * for each key-value mapping, followed by a null pair.
1455 * The key-value mappings are emitted in no particular order.
1456 */
1457 @SuppressWarnings("unchecked")
1458 private void writeObject(java.io.ObjectOutputStream s)
1459 throws java.io.IOException {
1460 if (segments == null) { // for serialization compatibility
1461 segments = (Segment<K,V>[])
1462 new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
1463 for (int i = 0; i < segments.length; ++i)
1464 segments[i] = new Segment<K,V>(loadFactor);
1465 }
1466 s.defaultWriteObject();
1467 new HashIterator().writeEntries(s);
1468 s.writeObject(null);
1469 s.writeObject(null);
1470 segments = null; // throw away
1471 }
1472
1473 /**
1474 * Reconstitutes the instance from a
1475 * stream (i.e., deserializes it).
1476 * @param s the stream
1477 */
1478 @SuppressWarnings("unchecked")
1479 private void readObject(java.io.ObjectInputStream s)
1480 throws java.io.IOException, ClassNotFoundException {
1481 s.defaultReadObject();
1482 // find load factor in a segment, if one exists
1483 if (segments != null && segments.length != 0)
1484 this.loadFactor = segments[0].loadFactor;
1485 else
1486 this.loadFactor = DEFAULT_LOAD_FACTOR;
1487 this.initCap = DEFAULT_CAPACITY;
1488 LongAdder ct = new LongAdder(); // force final field write
1489 UNSAFE.putObjectVolatile(this, counterOffset, ct);
1490 this.segments = null; // unneeded
1491
1492 // Read the keys and values, and put the mappings in the table
1493 for (;;) {
1494 K key = (K) s.readObject();
1495 V value = (V) s.readObject();
1496 if (key == null)
1497 break;
1498 put(key, value);
1499 }
1500 }
1501
1502 // Unsafe mechanics
1503 private static final sun.misc.Unsafe UNSAFE;
1504 private static final long counterOffset;
1505 private static final long resizingOffset;
1506 private static final long ABASE;
1507 private static final int ASHIFT;
1508
1509 static {
1510 int ss;
1511 try {
1512 UNSAFE = getUnsafe();
1513 Class<?> k = ConcurrentHashMapV8.class;
1514 counterOffset = UNSAFE.objectFieldOffset
1515 (k.getDeclaredField("counter"));
1516 resizingOffset = UNSAFE.objectFieldOffset
1517 (k.getDeclaredField("resizing"));
1518 Class<?> sc = Node[].class;
1519 ABASE = UNSAFE.arrayBaseOffset(sc);
1520 ss = UNSAFE.arrayIndexScale(sc);
1521 } catch (Exception e) {
1522 throw new Error(e);
1523 }
1524 if ((ss & (ss-1)) != 0)
1525 throw new Error("data type scale not a power of two");
1526 ASHIFT = 31 - Integer.numberOfLeadingZeros(ss);
1527 }
1528
1529 /**
1530 * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
1531 * Replace with a simple call to Unsafe.getUnsafe when integrating
1532 * into a jdk.
1533 *
1534 * @return a sun.misc.Unsafe
1535 */
1536 private static sun.misc.Unsafe getUnsafe() {
1537 try {
1538 return sun.misc.Unsafe.getUnsafe();
1539 } catch (SecurityException se) {
1540 try {
1541 return java.security.AccessController.doPrivileged
1542 (new java.security
1543 .PrivilegedExceptionAction<sun.misc.Unsafe>() {
1544 public sun.misc.Unsafe run() throws Exception {
1545 java.lang.reflect.Field f = sun.misc
1546 .Unsafe.class.getDeclaredField("theUnsafe");
1547 f.setAccessible(true);
1548 return (sun.misc.Unsafe) f.get(null);
1549 }});
1550 } catch (java.security.PrivilegedActionException e) {
1551 throw new RuntimeException("Could not initialize intrinsics",
1552 e.getCause());
1553 }
1554 }
1555 }
1556
1557 }