1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package net.sf.ehcache.store.chm;
16
17 import java.io.IOException;
18 import java.io.Serializable;
19 import java.util.AbstractCollection;
20 import java.util.AbstractMap;
21 import java.util.AbstractSet;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.ConcurrentModificationException;
25 import java.util.Enumeration;
26 import java.util.HashMap;
27 import java.util.Hashtable;
28 import java.util.Iterator;
29 import java.util.Map;
30 import java.util.NoSuchElementException;
31 import java.util.Set;
32 import java.util.concurrent.ConcurrentMap;
33 import java.util.concurrent.locks.ReentrantReadWriteLock;
34
35 import net.sf.ehcache.util.FindBugsSuppressWarnings;
36
37 /***
38 * A hash table supporting full concurrency of retrievals and
39 * adjustable expected concurrency for updates. This class obeys the
40 * same functional specification as {@link java.util.Hashtable}, and
41 * includes versions of methods corresponding to each method of
42 * <tt>Hashtable</tt>. However, even though all operations are
43 * thread-safe, retrieval operations do <em>not</em> entail locking,
44 * and there is <em>not</em> any support for locking the entire table
45 * in a way that prevents all access. This class is fully
46 * interoperable with <tt>Hashtable</tt> in programs that rely on its
47 * thread safety but not on its synchronization details.
48 *
49 * <p> Retrieval operations (including <tt>get</tt>) generally do not
50 * block, so may overlap with update operations (including
51 * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results
52 * of the most recently <em>completed</em> update operations holding
53 * upon their onset. For aggregate operations such as <tt>putAll</tt>
54 * and <tt>clear</tt>, concurrent retrievals may reflect insertion or
55 * removal of only some entries. Similarly, Iterators and
56 * Enumerations return elements reflecting the state of the hash table
57 * at some point at or since the creation of the iterator/enumeration.
58 * They do <em>not</em> throw {@link ConcurrentModificationException}.
59 * However, iterators are designed to be used by only one thread at a time.
60 *
61 * <p> The allowed concurrency among update operations is guided by
62 * the optional <tt>concurrencyLevel</tt> constructor argument
63 * (default <tt>16</tt>), which is used as a hint for internal sizing. The
64 * table is internally partitioned to try to permit the indicated
65 * number of concurrent updates without contention. Because placement
66 * in hash tables is essentially random, the actual concurrency will
67 * vary. Ideally, you should choose a value to accommodate as many
68 * threads as will ever concurrently modify the table. Using a
69 * significantly higher value than you need can waste space and time,
70 * and a significantly lower value can lead to thread contention. But
71 * overestimates and underestimates within an order of magnitude do
72 * not usually have much noticeable impact. A value of one is
73 * appropriate when it is known that only one thread will modify and
74 * all others will only read. Also, resizing this or any other kind of
75 * hash table is a relatively slow operation, so, when possible, it is
76 * a good idea to provide estimates of expected table sizes in
77 * constructors.
78 *
79 * <p>This class and its views and iterators implement all of the
80 * <em>optional</em> methods of the {@link Map} and {@link Iterator}
81 * interfaces.
82 *
83 * <p> Like {@link Hashtable} but unlike {@link HashMap}, this class
84 * does <em>not</em> allow <tt>null</tt> to be used as a key or value.
85 *
86 * <p>This class is a member of the
87 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
88 * Java Collections Framework</a>.
89 *
90 * @since 1.5
91 * @author Doug Lea
92 * @param <K> the type of keys maintained by this map
93 * @param <V> the type of mapped values
94 */
95 public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
96 implements ConcurrentMap<K, V>, Serializable {
97 private static final long serialVersionUID = 7249069246763182397L;
98
99
100
101
102
103
104
105
106 /***
107 * The default initial capacity for this table,
108 * used when not otherwise specified in a constructor.
109 */
110 static final int DEFAULT_INITIAL_CAPACITY = 16;
111
112 /***
113 * The default load factor for this table, used when not
114 * otherwise specified in a constructor.
115 */
116 static final float DEFAULT_LOAD_FACTOR = 0.75f;
117
118 /***
119 * The default concurrency level for this table, used when not
120 * otherwise specified in a constructor.
121 */
122 static final int DEFAULT_CONCURRENCY_LEVEL = 16;
123
124 /***
125 * The maximum capacity, used if a higher value is implicitly
126 * specified by either of the constructors with arguments. MUST
127 * be a power of two <= 1<<30 to ensure that entries are indexable
128 * using ints.
129 */
130 static final int MAXIMUM_CAPACITY = 1 << 30;
131
132 /***
133 * The maximum number of segments to allow; used to bound
134 * constructor arguments.
135 */
136 static final int MAX_SEGMENTS = 1 << 16;
137
138 /***
139 * Number of unsynchronized retries in size and containsValue
140 * methods before resorting to locking. This is used to avoid
141 * unbounded retries if tables undergo continuous modification
142 * which would make it impossible to obtain an accurate result.
143 */
144 static final int RETRIES_BEFORE_LOCK = 2;
145
146
147
148 /***
149 * Mask value for indexing into segments. The upper bits of a
150 * key's hash code are used to choose the segment.
151 */
152 final int segmentMask;
153
154 /***
155 * Shift value for indexing within segments.
156 */
157 final int segmentShift;
158
159 /***
160 * The segments, each of which is a specialized hash table
161 */
162 final Segment<K,V>[] segments;
163
164 transient Set<K> keySet;
165 transient Set<Map.Entry<K,V>> entrySet;
166 transient Collection<V> values;
167
168
169
170 /***
171 * Applies a supplemental hash function to a given hashCode, which
172 * defends against poor quality hash functions. This is critical
173 * because ConcurrentHashMap uses power-of-two length hash tables,
174 * that otherwise encounter collisions for hashCodes that do not
175 * differ in lower or upper bits.
176 */
177 protected static int hash(int h) {
178
179
180 h += (h << 15) ^ 0xffffcd7d;
181 h ^= (h >>> 10);
182 h += (h << 3);
183 h ^= (h >>> 6);
184 h += (h << 2) + (h << 14);
185 return h ^ (h >>> 16);
186 }
187
188 /***
189 * Returns the segment that should be used for key with given hash
190 * @param hash the hash code for the key
191 * @return the segment
192 */
193 final Segment<K,V> segmentFor(int hash) {
194 return segments[(hash >>> segmentShift) & segmentMask];
195 }
196
197
198
199 /***
200 * ConcurrentHashMap list entry. Note that this is never exported
201 * out as a user-visible Map.Entry.
202 *
203 * Because the value field is volatile, not final, it is legal wrt
204 * the Java Memory Model for an unsynchronized reader to see null
205 * instead of initial value when read via a data race. Although a
206 * reordering leading to this is not likely to ever actually
207 * occur, the Segment.readValueUnderLock method is used as a
208 * backup in case a null (pre-initialized) value is ever seen in
209 * an unsynchronized access method.
210 */
211 static final class HashEntry<K,V> {
212 final K key;
213 final int hash;
214 volatile V value;
215 final HashEntry<K,V> next;
216
217 HashEntry(K key, int hash, HashEntry<K,V> next, V value) {
218 this.key = key;
219 this.hash = hash;
220 this.next = next;
221 this.value = value;
222 }
223
224 @SuppressWarnings("unchecked")
225 static final <K,V> HashEntry<K,V>[] newArray(int i) {
226 return new HashEntry[i];
227 }
228 }
229
230 /***
231 * Segments are specialized versions of hash tables. This
232 * subclasses from ReentrantLock opportunistically, just to
233 * simplify some locking and avoid separate construction.
234 */
235 static final class Segment<K,V> extends ReentrantReadWriteLock implements Serializable {
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273 private static final long serialVersionUID = 2249069246763182397L;
274
275 /***
276 * The number of elements in this segment's region.
277 */
278 transient volatile int count;
279
280 /***
281 * Number of updates that alter the size of the table. This is
282 * used during bulk-read methods to make sure they see a
283 * consistent snapshot: If modCounts change during a traversal
284 * of segments computing size or checking containsValue, then
285 * we might have an inconsistent view of state so (usually)
286 * must retry.
287 */
288 transient int modCount;
289
290 /***
291 * The table is rehashed when its size exceeds this threshold.
292 * (The value of this field is always <tt>(int)(capacity *
293 * loadFactor)</tt>.)
294 */
295 transient int threshold;
296
297 /***
298 * The per-segment table.
299 */
300 transient volatile HashEntry<K,V>[] table;
301
302 /***
303 * The load factor for the hash table. Even though this value
304 * is same for all segments, it is replicated to avoid needing
305 * links to outer object.
306 * @serial
307 */
308 final float loadFactor;
309
310 Segment(int initialCapacity, float lf) {
311 loadFactor = lf;
312 setTable(HashEntry.<K,V>newArray(initialCapacity));
313 }
314
315 @SuppressWarnings("unchecked")
316 static final <K,V> Segment<K,V>[] newArray(int i) {
317 return new Segment[i];
318 }
319
320 /***
321 * Sets table to new HashEntry array.
322 * Call only while holding lock or in constructor.
323 */
324 void setTable(HashEntry<K,V>[] newTable) {
325 threshold = (int)(newTable.length * loadFactor);
326 table = newTable;
327 }
328
329 /***
330 * Returns properly casted first entry of bin for given hash.
331 */
332 HashEntry<K,V> getFirst(int hash) {
333 HashEntry<K,V>[] tab = table;
334 return tab[hash & (tab.length - 1)];
335 }
336
337
338
339 V get(Object key, int hash) {
340 readLock().lock();
341 try {
342 if (count != 0) {
343 HashEntry<K,V> e = getFirst(hash);
344 while (e != null) {
345 if (e.hash == hash && key.equals(e.key)) {
346 return e.value;
347 }
348 e = e.next;
349 }
350 }
351 return null;
352 } finally {
353 readLock().unlock();
354 }
355 }
356
357 boolean containsKey(Object key, int hash) {
358 readLock().lock();
359 try {
360 if (count != 0) {
361 HashEntry<K,V> e = getFirst(hash);
362 while (e != null) {
363 if (e.hash == hash && key.equals(e.key))
364 return true;
365 e = e.next;
366 }
367 }
368 return false;
369 } finally {
370 readLock().unlock();
371 }
372 }
373
374 boolean containsValue(Object value) {
375 readLock().lock();
376 try {
377 if (count != 0) {
378 HashEntry<K,V>[] tab = table;
379 int len = tab.length;
380 for (int i = 0 ; i < len; i++) {
381 for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
382 V v = e.value;
383 if (value.equals(v))
384 return true;
385 }
386 }
387 }
388 return false;
389 } finally {
390 readLock().unlock();
391 }
392 }
393
394 boolean replace(K key, int hash, V oldValue, V newValue) {
395 writeLock().lock();
396 try {
397 HashEntry<K,V> e = getFirst(hash);
398 while (e != null && (e.hash != hash || !key.equals(e.key)))
399 e = e.next;
400
401 boolean replaced = false;
402 if (e != null && oldValue.equals(e.value)) {
403 replaced = true;
404 e.value = newValue;
405 }
406 return replaced;
407 } finally {
408 writeLock().unlock();
409 }
410 }
411
412 V replace(K key, int hash, V newValue) {
413 writeLock().lock();
414 try {
415 HashEntry<K,V> e = getFirst(hash);
416 while (e != null && (e.hash != hash || !key.equals(e.key)))
417 e = e.next;
418
419 V oldValue = null;
420 if (e != null) {
421 oldValue = e.value;
422 e.value = newValue;
423 }
424 return oldValue;
425 } finally {
426 writeLock().unlock();
427 }
428 }
429
430
431 V put(K key, int hash, V value, boolean onlyIfAbsent) {
432 writeLock().lock();
433 try {
434 int c = count;
435 if (c++ > threshold)
436 rehash();
437 HashEntry<K,V>[] tab = table;
438 int index = hash & (tab.length - 1);
439 HashEntry<K,V> first = tab[index];
440 HashEntry<K,V> e = first;
441 while (e != null && (e.hash != hash || !key.equals(e.key)))
442 e = e.next;
443
444 V oldValue;
445 if (e != null) {
446 oldValue = e.value;
447 if (!onlyIfAbsent)
448 e.value = value;
449 }
450 else {
451 oldValue = null;
452 ++modCount;
453 tab[index] = new HashEntry<K,V>(key, hash, first, value);
454 count = c;
455 }
456 return oldValue;
457 } finally {
458 writeLock().unlock();
459 }
460 }
461
462 void rehash() {
463 HashEntry<K,V>[] oldTable = table;
464 int oldCapacity = oldTable.length;
465 if (oldCapacity >= MAXIMUM_CAPACITY)
466 return;
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482 HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1);
483 threshold = (int)(newTable.length * loadFactor);
484 int sizeMask = newTable.length - 1;
485 for (int i = 0; i < oldCapacity ; i++) {
486
487
488 HashEntry<K,V> e = oldTable[i];
489
490 if (e != null) {
491 HashEntry<K,V> next = e.next;
492 int idx = e.hash & sizeMask;
493
494
495 if (next == null)
496 newTable[idx] = e;
497
498 else {
499
500 HashEntry<K,V> lastRun = e;
501 int lastIdx = idx;
502 for (HashEntry<K,V> last = next;
503 last != null;
504 last = last.next) {
505 int k = last.hash & sizeMask;
506 if (k != lastIdx) {
507 lastIdx = k;
508 lastRun = last;
509 }
510 }
511 newTable[lastIdx] = lastRun;
512
513
514 for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
515 int k = p.hash & sizeMask;
516 HashEntry<K,V> n = newTable[k];
517 newTable[k] = new HashEntry<K,V>(p.key, p.hash,
518 n, p.value);
519 }
520 }
521 }
522 }
523 table = newTable;
524 }
525
526 /***
527 * Remove; match on key only if value null, else match both.
528 */
529 V remove(Object key, int hash, Object value) {
530 writeLock().lock();
531 try {
532 int c = count - 1;
533 HashEntry<K,V>[] tab = table;
534 int index = hash & (tab.length - 1);
535 HashEntry<K,V> first = tab[index];
536 HashEntry<K,V> e = first;
537 while (e != null && (e.hash != hash || !key.equals(e.key)))
538 e = e.next;
539
540 V oldValue = null;
541 if (e != null) {
542 V v = e.value;
543 if (value == null || value.equals(v)) {
544 oldValue = v;
545
546
547
548 ++modCount;
549 HashEntry<K,V> newFirst = e.next;
550 for (HashEntry<K,V> p = first; p != e; p = p.next)
551 newFirst = new HashEntry<K,V>(p.key, p.hash,
552 newFirst, p.value);
553 tab[index] = newFirst;
554 count = c;
555 }
556 }
557 return oldValue;
558 } finally {
559 writeLock().unlock();
560 }
561 }
562
563 void clear() {
564 writeLock().lock();
565 try {
566 if (count != 0) {
567 HashEntry<K,V>[] tab = table;
568 for (int i = 0; i < tab.length ; i++)
569 tab[i] = null;
570 ++modCount;
571 count = 0;
572 }
573 } finally {
574 writeLock().unlock();
575 }
576 }
577 }
578
579
580
581
582
583 /***
584 * Creates a new, empty map with the specified initial
585 * capacity, load factor and concurrency level.
586 *
587 * @param initialCapacity the initial capacity. The implementation
588 * performs internal sizing to accommodate this many elements.
589 * @param loadFactor the load factor threshold, used to control resizing.
590 * Resizing may be performed when the average number of elements per
591 * bin exceeds this threshold.
592 * @param concurrencyLevel the estimated number of concurrently
593 * updating threads. The implementation performs internal sizing
594 * to try to accommodate this many threads.
595 * @throws IllegalArgumentException if the initial capacity is
596 * negative or the load factor or concurrencyLevel are
597 * nonpositive.
598 */
599 public ConcurrentHashMap(int initialCapacity,
600 float loadFactor, int concurrencyLevel) {
601 if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
602 throw new IllegalArgumentException();
603
604 if (concurrencyLevel > MAX_SEGMENTS)
605 concurrencyLevel = MAX_SEGMENTS;
606
607
608 int sshift = 0;
609 int ssize = 1;
610 while (ssize < concurrencyLevel) {
611 ++sshift;
612 ssize <<= 1;
613 }
614 segmentShift = 32 - sshift;
615 segmentMask = ssize - 1;
616 this.segments = Segment.newArray(ssize);
617
618 if (initialCapacity > MAXIMUM_CAPACITY)
619 initialCapacity = MAXIMUM_CAPACITY;
620 int c = initialCapacity / ssize;
621 if (c * ssize < initialCapacity)
622 ++c;
623 int cap = 1;
624 while (cap < c)
625 cap <<= 1;
626
627 for (int i = 0; i < this.segments.length; ++i)
628 this.segments[i] = new Segment<K,V>(cap, loadFactor);
629 }
630
631 /***
632 * Creates a new, empty map with the specified initial capacity,
633 * and with default load factor (0.75) and concurrencyLevel (16).
634 *
635 * @param initialCapacity the initial capacity. The implementation
636 * performs internal sizing to accommodate this many elements.
637 * @throws IllegalArgumentException if the initial capacity of
638 * elements is negative.
639 */
640 public ConcurrentHashMap(int initialCapacity) {
641 this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
642 }
643
644 /***
645 * Creates a new, empty map with a default initial capacity (16),
646 * load factor (0.75) and concurrencyLevel (16).
647 */
648 public ConcurrentHashMap() {
649 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
650 }
651
652 /***
653 * Creates a new map with the same mappings as the given map.
654 * The map is created with a capacity of 1.5 times the number
655 * of mappings in the given map or 16 (whichever is greater),
656 * and a default load factor (0.75) and concurrencyLevel (16).
657 *
658 * @param m the map
659 */
660 public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
661 this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
662 DEFAULT_INITIAL_CAPACITY),
663 DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
664 putAll(m);
665 }
666
667 /***
668 * Returns <tt>true</tt> if this map contains no key-value mappings.
669 *
670 * @return <tt>true</tt> if this map contains no key-value mappings
671 */
672 public boolean isEmpty() {
673 final Segment<K,V>[] segments = this.segments;
674
675
676
677
678
679
680
681
682
683 int[] mc = new int[segments.length];
684 int mcsum = 0;
685 for (int i = 0; i < segments.length; ++i) {
686 if (segments[i].count != 0)
687 return false;
688 else
689 mcsum += mc[i] = segments[i].modCount;
690 }
691
692
693
694 if (mcsum != 0) {
695 for (int i = 0; i < segments.length; ++i) {
696 if (segments[i].count != 0 ||
697 mc[i] != segments[i].modCount)
698 return false;
699 }
700 }
701 return true;
702 }
703
704 /***
705 * Returns the number of key-value mappings in this map. If the
706 * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
707 * <tt>Integer.MAX_VALUE</tt>.
708 *
709 * @return the number of key-value mappings in this map
710 */
711 @FindBugsSuppressWarnings("UL_UNRELEASED_LOCK")
712 public int size() {
713 final Segment<K,V>[] segments = this.segments;
714 long sum = 0;
715 long check = 0;
716 int[] mc = new int[segments.length];
717
718
719 for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
720 check = 0;
721 sum = 0;
722 int mcsum = 0;
723 for (int i = 0; i < segments.length; ++i) {
724 sum += segments[i].count;
725 mcsum += mc[i] = segments[i].modCount;
726 }
727 if (mcsum != 0) {
728 for (int i = 0; i < segments.length; ++i) {
729 check += segments[i].count;
730 if (mc[i] != segments[i].modCount) {
731 check = -1;
732 break;
733 }
734 }
735 }
736 if (check == sum)
737 break;
738 }
739 if (check != sum) {
740 sum = 0;
741 for (int i = 0; i < segments.length; ++i)
742 segments[i].readLock().lock();
743 try {
744 for (int i = 0; i < segments.length; ++i)
745 sum += segments[i].count;
746 } finally {
747 for (int i = 0; i < segments.length; ++i)
748 segments[i].readLock().unlock();
749 }
750 }
751 if (sum > Integer.MAX_VALUE)
752 return Integer.MAX_VALUE;
753 else
754 return (int)sum;
755 }
756
757 /***
758 * Returns the value to which the specified key is mapped,
759 * or {@code null} if this map contains no mapping for the key.
760 *
761 * <p>More formally, if this map contains a mapping from a key
762 * {@code k} to a value {@code v} such that {@code key.equals(k)},
763 * then this method returns {@code v}; otherwise it returns
764 * {@code null}. (There can be at most one such mapping.)
765 *
766 * @throws NullPointerException if the specified key is null
767 */
768 public V get(Object key) {
769 int hash = hash(key.hashCode());
770 return segmentFor(hash).get(key, hash);
771 }
772
773 /***
774 * Tests if the specified object is a key in this table.
775 *
776 * @param key possible key
777 * @return <tt>true</tt> if and only if the specified object
778 * is a key in this table, as determined by the
779 * <tt>equals</tt> method; <tt>false</tt> otherwise.
780 * @throws NullPointerException if the specified key is null
781 */
782 public boolean containsKey(Object key) {
783 int hash = hash(key.hashCode());
784 return segmentFor(hash).containsKey(key, hash);
785 }
786
787 /***
788 * Returns <tt>true</tt> if this map maps one or more keys to the
789 * specified value. Note: This method requires a full internal
790 * traversal of the hash table, and so is much slower than
791 * method <tt>containsKey</tt>.
792 *
793 * @param value value whose presence in this map is to be tested
794 * @return <tt>true</tt> if this map maps one or more keys to the
795 * specified value
796 * @throws NullPointerException if the specified value is null
797 */
798 @FindBugsSuppressWarnings("UL_UNRELEASED_LOCK")
799 public boolean containsValue(Object value) {
800 if (value == null)
801 throw new NullPointerException();
802
803
804
805 final Segment<K,V>[] segments = this.segments;
806 int[] mc = new int[segments.length];
807
808
809 for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
810 int sum = 0;
811 int mcsum = 0;
812 for (int i = 0; i < segments.length; ++i) {
813 int c = segments[i].count;
814 mcsum += mc[i] = segments[i].modCount;
815 if (segments[i].containsValue(value))
816 return true;
817 }
818 boolean cleanSweep = true;
819 if (mcsum != 0) {
820 for (int i = 0; i < segments.length; ++i) {
821 int c = segments[i].count;
822 if (mc[i] != segments[i].modCount) {
823 cleanSweep = false;
824 break;
825 }
826 }
827 }
828 if (cleanSweep)
829 return false;
830 }
831
832
833 for (int i = 0; i < segments.length; ++i)
834 segments[i].readLock().lock();
835 try {
836 for (int i = 0; i < segments.length; ++i) {
837 if (segments[i].containsValue(value)) {
838 return true;
839 }
840 }
841 } finally {
842 for (int i = 0; i < segments.length; ++i)
843 segments[i].readLock().unlock();
844 }
845 return false;
846 }
847
848 /***
849 * Legacy method testing if some key maps into the specified value
850 * in this table. This method is identical in functionality to
851 * {@link #containsValue}, and exists solely to ensure
852 * full compatibility with class {@link java.util.Hashtable},
853 * which supported this method prior to introduction of the
854 * Java Collections framework.
855
856 * @param value a value to search for
857 * @return <tt>true</tt> if and only if some key maps to the
858 * <tt>value</tt> argument in this table as
859 * determined by the <tt>equals</tt> method;
860 * <tt>false</tt> otherwise
861 * @throws NullPointerException if the specified value is null
862 */
863 public boolean contains(Object value) {
864 return containsValue(value);
865 }
866
867 /***
868 * Maps the specified key to the specified value in this table.
869 * Neither the key nor the value can be null.
870 *
871 * <p> The value can be retrieved by calling the <tt>get</tt> method
872 * with a key that is equal to the original key.
873 *
874 * @param key key with which the specified value is to be associated
875 * @param value value to be associated with the specified key
876 * @return the previous value associated with <tt>key</tt>, or
877 * <tt>null</tt> if there was no mapping for <tt>key</tt>
878 * @throws NullPointerException if the specified key or value is null
879 */
880 public V put(K key, V value) {
881 if (value == null)
882 throw new NullPointerException();
883 int hash = hash(key.hashCode());
884 return segmentFor(hash).put(key, hash, value, false);
885 }
886
887 /***
888 * {@inheritDoc}
889 *
890 * @return the previous value associated with the specified key,
891 * or <tt>null</tt> if there was no mapping for the key
892 * @throws NullPointerException if the specified key or value is null
893 */
894 public V putIfAbsent(K key, V value) {
895 if (value == null)
896 throw new NullPointerException();
897 int hash = hash(key.hashCode());
898 return segmentFor(hash).put(key, hash, value, true);
899 }
900
901 /***
902 * Copies all of the mappings from the specified map to this one.
903 * These mappings replace any mappings that this map had for any of the
904 * keys currently in the specified map.
905 *
906 * @param m mappings to be stored in this map
907 */
908 public void putAll(Map<? extends K, ? extends V> m) {
909 for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
910 put(e.getKey(), e.getValue());
911 }
912
913 /***
914 * Removes the key (and its corresponding value) from this map.
915 * This method does nothing if the key is not in the map.
916 *
917 * @param key the key that needs to be removed
918 * @return the previous value associated with <tt>key</tt>, or
919 * <tt>null</tt> if there was no mapping for <tt>key</tt>
920 * @throws NullPointerException if the specified key is null
921 */
922 public V remove(Object key) {
923 int hash = hash(key.hashCode());
924 return segmentFor(hash).remove(key, hash, null);
925 }
926
927 /***
928 * {@inheritDoc}
929 *
930 * @throws NullPointerException if the specified key is null
931 */
932 public boolean remove(Object key, Object value) {
933 int hash = hash(key.hashCode());
934 if (value == null)
935 return false;
936 return segmentFor(hash).remove(key, hash, value) != null;
937 }
938
939 /***
940 * {@inheritDoc}
941 *
942 * @throws NullPointerException if any of the arguments are null
943 */
944 public boolean replace(K key, V oldValue, V newValue) {
945 if (oldValue == null || newValue == null)
946 throw new NullPointerException();
947 int hash = hash(key.hashCode());
948 return segmentFor(hash).replace(key, hash, oldValue, newValue);
949 }
950
951 /***
952 * {@inheritDoc}
953 *
954 * @return the previous value associated with the specified key,
955 * or <tt>null</tt> if there was no mapping for the key
956 * @throws NullPointerException if the specified key or value is null
957 */
958 public V replace(K key, V value) {
959 if (value == null)
960 throw new NullPointerException();
961 int hash = hash(key.hashCode());
962 return segmentFor(hash).replace(key, hash, value);
963 }
964
965 /***
966 * Removes all of the mappings from this map.
967 */
968 public void clear() {
969 for (int i = 0; i < segments.length; ++i)
970 segments[i].clear();
971 }
972
973 /***
974 * Returns a {@link Set} view of the keys contained in this map.
975 * The set is backed by the map, so changes to the map are
976 * reflected in the set, and vice-versa. The set supports element
977 * removal, which removes the corresponding mapping from this map,
978 * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
979 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
980 * operations. It does not support the <tt>add</tt> or
981 * <tt>addAll</tt> operations.
982 *
983 * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
984 * that will never throw {@link ConcurrentModificationException},
985 * and guarantees to traverse elements as they existed upon
986 * construction of the iterator, and may (but is not guaranteed to)
987 * reflect any modifications subsequent to construction.
988 */
989 public Set<K> keySet() {
990 Set<K> ks = keySet;
991 return (ks != null) ? ks : (keySet = new KeySet());
992 }
993
994 /***
995 * Returns a {@link Collection} view of the values contained in this map.
996 * The collection is backed by the map, so changes to the map are
997 * reflected in the collection, and vice-versa. The collection
998 * supports element removal, which removes the corresponding
999 * mapping from this map, via the <tt>Iterator.remove</tt>,
1000 * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
1001 * <tt>retainAll</tt>, and <tt>clear</tt> operations. It does not
1002 * support the <tt>add</tt> or <tt>addAll</tt> operations.
1003 *
1004 * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
1005 * that will never throw {@link ConcurrentModificationException},
1006 * and guarantees to traverse elements as they existed upon
1007 * construction of the iterator, and may (but is not guaranteed to)
1008 * reflect any modifications subsequent to construction.
1009 */
1010 public Collection<V> values() {
1011 Collection<V> vs = values;
1012 return (vs != null) ? vs : (values = new Values());
1013 }
1014
1015 /***
1016 * Returns a {@link Set} view of the mappings contained in this map.
1017 * The set is backed by the map, so changes to the map are
1018 * reflected in the set, and vice-versa. The set supports element
1019 * removal, which removes the corresponding mapping from the map,
1020 * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
1021 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
1022 * operations. It does not support the <tt>add</tt> or
1023 * <tt>addAll</tt> operations.
1024 *
1025 * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
1026 * that will never throw {@link ConcurrentModificationException},
1027 * and guarantees to traverse elements as they existed upon
1028 * construction of the iterator, and may (but is not guaranteed to)
1029 * reflect any modifications subsequent to construction.
1030 */
1031 public Set<Map.Entry<K,V>> entrySet() {
1032 Set<Map.Entry<K,V>> es = entrySet;
1033 return (es != null) ? es : (entrySet = new EntrySet());
1034 }
1035
1036 /***
1037 * Returns an enumeration of the keys in this table.
1038 *
1039 * @return an enumeration of the keys in this table
1040 * @see #keySet()
1041 */
1042 public Enumeration<K> keys() {
1043 return new KeyIterator();
1044 }
1045
1046 /***
1047 * Returns an enumeration of the values in this table.
1048 *
1049 * @return an enumeration of the values in this table
1050 * @see #values()
1051 */
1052 public Enumeration<V> elements() {
1053 return new ValueIterator();
1054 }
1055
1056
1057
1058 abstract class HashIterator {
1059 int nextSegmentIndex;
1060 int nextTableIndex;
1061 HashEntry<K,V>[] currentTable;
1062 HashEntry<K, V> nextEntry;
1063 HashEntry<K, V> lastReturned;
1064
1065 HashIterator() {
1066 nextSegmentIndex = segments.length - 1;
1067 nextTableIndex = -1;
1068 advance();
1069 }
1070
1071 public boolean hasMoreElements() { return hasNext(); }
1072
1073 final void advance() {
1074 if (nextEntry != null && (nextEntry = nextEntry.next) != null)
1075 return;
1076
1077 while (nextTableIndex >= 0) {
1078 if ( (nextEntry = currentTable[nextTableIndex--]) != null)
1079 return;
1080 }
1081
1082 while (nextSegmentIndex >= 0) {
1083 Segment<K,V> seg = segments[nextSegmentIndex--];
1084 if (seg.count != 0) {
1085 currentTable = seg.table;
1086 for (int j = currentTable.length - 1; j >= 0; --j) {
1087 if ( (nextEntry = currentTable[j]) != null) {
1088 nextTableIndex = j - 1;
1089 return;
1090 }
1091 }
1092 }
1093 }
1094 }
1095
1096 public boolean hasNext() { return nextEntry != null; }
1097
1098 HashEntry<K,V> nextEntry() {
1099 if (nextEntry == null)
1100 throw new NoSuchElementException();
1101 lastReturned = nextEntry;
1102 advance();
1103 return lastReturned;
1104 }
1105
1106 public void remove() {
1107 if (lastReturned == null)
1108 throw new IllegalStateException();
1109 ConcurrentHashMap.this.remove(lastReturned.key);
1110 lastReturned = null;
1111 }
1112 }
1113
1114 final class KeyIterator
1115 extends HashIterator
1116 implements Iterator<K>, Enumeration<K>
1117 {
1118 public K next() { return super.nextEntry().key; }
1119 public K nextElement() { return super.nextEntry().key; }
1120 }
1121
1122 final class ValueIterator
1123 extends HashIterator
1124 implements Iterator<V>, Enumeration<V>
1125 {
1126 public V next() { return super.nextEntry().value; }
1127 public V nextElement() { return super.nextEntry().value; }
1128 }
1129
1130 /***
1131 * Custom Entry class used by EntryIterator.next(), that relays
1132 * setValue changes to the underlying map.
1133 */
1134 final class WriteThroughEntry
1135 extends SimpleEntry<K,V>
1136 {
1137 WriteThroughEntry(K k, V v) {
1138 super(k,v);
1139 }
1140
1141 /***
1142 * Set our entry's value and write through to the map. The
1143 * value to return is somewhat arbitrary here. Since a
1144 * WriteThroughEntry does not necessarily track asynchronous
1145 * changes, the most recent "previous" value could be
1146 * different from what we return (or could even have been
1147 * removed in which case the put will re-establish). We do not
1148 * and cannot guarantee more.
1149 */
1150 public V setValue(V value) {
1151 if (value == null) throw new NullPointerException();
1152 V v = super.setValue(value);
1153 ConcurrentHashMap.this.put(getKey(), value);
1154 return v;
1155 }
1156 }
1157
1158 final class EntryIterator
1159 extends HashIterator
1160 implements Iterator<Entry<K,V>>
1161 {
1162 public Map.Entry<K,V> next() {
1163 HashEntry<K,V> e = super.nextEntry();
1164 return new WriteThroughEntry(e.key, e.value);
1165 }
1166 }
1167
1168 final class KeySet extends AbstractSet<K> {
1169 public Iterator<K> iterator() {
1170 return new KeyIterator();
1171 }
1172 public int size() {
1173 return ConcurrentHashMap.this.size();
1174 }
1175 public boolean isEmpty() {
1176 return ConcurrentHashMap.this.isEmpty();
1177 }
1178 public boolean contains(Object o) {
1179 return ConcurrentHashMap.this.containsKey(o);
1180 }
1181 public boolean remove(Object o) {
1182 return ConcurrentHashMap.this.remove(o) != null;
1183 }
1184 public void clear() {
1185 ConcurrentHashMap.this.clear();
1186 }
1187 public Object[] toArray() {
1188 Collection<K> c = new ArrayList<K>();
1189 for (Iterator<K> i = iterator(); i.hasNext(); )
1190 c.add(i.next());
1191 return c.toArray();
1192 }
1193 public <T> T[] toArray(T[] a) {
1194 Collection<K> c = new ArrayList<K>();
1195 for (Iterator<K> i = iterator(); i.hasNext(); )
1196 c.add(i.next());
1197 return c.toArray(a);
1198 }
1199 }
1200
1201 final class Values extends AbstractCollection<V> {
1202 public Iterator<V> iterator() {
1203 return new ValueIterator();
1204 }
1205 public int size() {
1206 return ConcurrentHashMap.this.size();
1207 }
1208 public boolean isEmpty() {
1209 return ConcurrentHashMap.this.isEmpty();
1210 }
1211 public boolean contains(Object o) {
1212 return ConcurrentHashMap.this.containsValue(o);
1213 }
1214 public void clear() {
1215 ConcurrentHashMap.this.clear();
1216 }
1217 public Object[] toArray() {
1218 Collection<V> c = new ArrayList<V>();
1219 for (Iterator<V> i = iterator(); i.hasNext(); )
1220 c.add(i.next());
1221 return c.toArray();
1222 }
1223 public <T> T[] toArray(T[] a) {
1224 Collection<V> c = new ArrayList<V>();
1225 for (Iterator<V> i = iterator(); i.hasNext(); )
1226 c.add(i.next());
1227 return c.toArray(a);
1228 }
1229 }
1230
1231 final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1232 public Iterator<Map.Entry<K,V>> iterator() {
1233 return new EntryIterator();
1234 }
1235 public boolean contains(Object o) {
1236 if (!(o instanceof Map.Entry))
1237 return false;
1238 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1239 V v = ConcurrentHashMap.this.get(e.getKey());
1240 return v != null && v.equals(e.getValue());
1241 }
1242 public boolean remove(Object o) {
1243 if (!(o instanceof Map.Entry))
1244 return false;
1245 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1246 return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
1247 }
1248 public int size() {
1249 return ConcurrentHashMap.this.size();
1250 }
1251 public boolean isEmpty() {
1252 return ConcurrentHashMap.this.isEmpty();
1253 }
1254 public void clear() {
1255 ConcurrentHashMap.this.clear();
1256 }
1257 public Object[] toArray() {
1258 Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>();
1259 for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); )
1260 c.add(i.next());
1261 return c.toArray();
1262 }
1263 public <T> T[] toArray(T[] a) {
1264 Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>();
1265 for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); )
1266 c.add(i.next());
1267 return c.toArray(a);
1268 }
1269 }
1270
1271 /***
1272 * This duplicates java.util.AbstractMap.SimpleEntry until this class
1273 * is made accessible.
1274 */
1275 static class SimpleEntry<K,V> implements Entry<K,V> {
1276 K key;
1277 V value;
1278
1279 public SimpleEntry(K key, V value) {
1280 this.key = key;
1281 this.value = value;
1282 }
1283
1284 public SimpleEntry(Entry<K,V> e) {
1285 this.key = e.getKey();
1286 this.value = e.getValue();
1287 }
1288
1289 public K getKey() {
1290 return key;
1291 }
1292
1293 public V getValue() {
1294 return value;
1295 }
1296
1297 public V setValue(V value) {
1298 V oldValue = this.value;
1299 this.value = value;
1300 return oldValue;
1301 }
1302
1303 public boolean equals(Object o) {
1304 if (!(o instanceof Map.Entry))
1305 return false;
1306 Map.Entry e = (Map.Entry)o;
1307 return eq(key, e.getKey()) && eq(value, e.getValue());
1308 }
1309
1310 public int hashCode() {
1311 return ((key == null) ? 0 : key.hashCode()) ^
1312 ((value == null) ? 0 : value.hashCode());
1313 }
1314
1315 public String toString() {
1316 return key + "=" + value;
1317 }
1318
1319 static boolean eq(Object o1, Object o2) {
1320 return (o1 == null ? o2 == null : o1.equals(o2));
1321 }
1322 }
1323
1324
1325
1326 /***
1327 * Save the state of the <tt>ConcurrentHashMap</tt> instance to a
1328 * stream (i.e., serialize it).
1329 * @param s the stream
1330 * @serialData
1331 * the key (Object) and value (Object)
1332 * for each key-value mapping, followed by a null pair.
1333 * The key-value mappings are emitted in no particular order.
1334 */
1335 private void writeObject(java.io.ObjectOutputStream s) throws IOException {
1336 s.defaultWriteObject();
1337
1338 for (int k = 0; k < segments.length; ++k) {
1339 Segment<K,V> seg = segments[k];
1340 seg.readLock().lock();
1341 try {
1342 HashEntry<K,V>[] tab = seg.table;
1343 for (int i = 0; i < tab.length; ++i) {
1344 for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
1345 s.writeObject(e.key);
1346 s.writeObject(e.value);
1347 }
1348 }
1349 } finally {
1350 seg.readLock().unlock();
1351 }
1352 }
1353 s.writeObject(null);
1354 s.writeObject(null);
1355 }
1356
1357 /***
1358 * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a
1359 * stream (i.e., deserialize it).
1360 * @param s the stream
1361 */
1362 private void readObject(java.io.ObjectInputStream s)
1363 throws IOException, ClassNotFoundException {
1364 s.defaultReadObject();
1365
1366
1367 for (int i = 0; i < segments.length; ++i) {
1368 segments[i].setTable(new HashEntry[1]);
1369 }
1370
1371
1372 for (;;) {
1373 K key = (K) s.readObject();
1374 V value = (V) s.readObject();
1375 if (key == null)
1376 break;
1377 put(key, value);
1378 }
1379 }
1380 }