1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package org.jdiagnose.concurrent;
27
28 import java.io.IOException;
29 import java.io.Serializable;
30 import java.util.AbstractCollection;
31 import java.util.AbstractMap;
32 import java.util.AbstractSet;
33 import java.util.Collection;
34 import java.util.Enumeration;
35 import java.util.Iterator;
36 import java.util.Map;
37 import java.util.NoSuchElementException;
38 import java.util.Set;
39
40
41 /***
42 * A version of Hashtable supporting
43 * concurrency for both retrievals and updates:
44 *
45 * <dl>
46 * <dt> Retrievals
47 *
48 * <dd> Retrievals may overlap updates. (This is the same policy as
49 * ConcurrentReaderHashMap.) Successful retrievals using get(key) and
50 * containsKey(key) usually run without locking. Unsuccessful
51 * retrievals (i.e., when the key is not present) do involve brief
52 * synchronization (locking). Because retrieval operations can
53 * ordinarily overlap with update operations (i.e., put, remove, and
54 * their derivatives), retrievals can only be guaranteed to return the
55 * results of the most recently <em>completed</em> operations holding
56 * upon their onset. Retrieval operations may or may not return
57 * results reflecting in-progress writing operations. However, the
58 * retrieval operations do always return consistent results -- either
59 * those holding before any single modification or after it, but never
60 * a nonsense result. For aggregate operations such as putAll and
61 * clear, concurrent reads may reflect insertion or removal of only
62 * some entries.
63 * <p>
64 *
65 * Iterators and Enumerations (i.e., those returned by
66 * keySet().iterator(), entrySet().iterator(), values().iterator(),
67 * keys(), and elements()) return elements reflecting the state of the
68 * hash table at some point at or since the creation of the
69 * iterator/enumeration. They will return at most one instance of
70 * each element (via next()/nextElement()), but might or might not
71 * reflect puts and removes that have been processed since they were
72 * created. They do <em>not</em> throw ConcurrentModificationException.
73 * However, these iterators are designed to be used by only one
74 * thread at a time. Passing an iterator across multiple threads may
75 * lead to unpredictable results if the table is being concurrently
76 * modified. <p>
77 *
78 *
79 * <dt> Updates
80 *
81 * <dd> This class supports a hard-wired preset <em>concurrency
82 * level</em> of 32. This allows a maximum of 32 put and/or remove
83 * operations to proceed concurrently. This level is an upper bound on
84 * concurrency, not a guarantee, since it interacts with how
85 * well-strewn elements are across bins of the table. (The preset
86 * value in part reflects the fact that even on large multiprocessors,
87 * factors other than synchronization tend to be bottlenecks when more
88 * than 32 threads concurrently attempt updates.)
89 * Additionally, operations triggering internal resizing and clearing
90 * do not execute concurrently with any operation.
91 * <p>
92 *
93 * There is <em>NOT</em> any support for locking the entire table to
94 * prevent updates. This makes it imposssible, for example, to
95 * add an element only if it is not already present, since another
96 * thread may be in the process of doing the same thing.
97 * If you need such capabilities, consider instead using the
98 * ConcurrentReaderHashMap class.
99 *
100 * </dl>
101 *
102 * Because of how concurrency control is split up, the
103 * size() and isEmpty() methods require accumulations across 32
104 * control segments, and so might be slightly slower than you expect.
105 * <p>
106 *
107 * This class may be used as a direct replacement for
108 * java.util.Hashtable in any application that does not rely
109 * on the ability to lock the entire table to prevent updates.
110 * As of this writing, it performs much faster than Hashtable in
111 * typical multi-threaded applications with multiple readers and writers.
112 * Like Hashtable but unlike java.util.HashMap,
113 * this class does NOT allow <tt>null</tt> to be used as a key or
114 * value.
115 * <p>
116 *
117 * Implementation note: A slightly
118 * faster implementation of this class will be possible once planned
119 * Java Memory Model revisions are in place.
120 *
121 * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
122
123 **/
124
125
126 public class ConcurrentHashMap
127 extends AbstractMap
128 implements Map, Cloneable, Serializable {
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 /***
166 * The hash table data.
167 */
168 protected transient Entry[] table;
169
170
171 /***
172 * The number of concurrency control segments.
173 * The value can be at most 32 since ints are used
174 * as bitsets over segments. Emprically, it doesn't
175 * seem to pay to decrease it either, so the value should be at least 32.
176 * In other words, do not redefine this :-)
177 **/
178
179 protected static final int CONCURRENCY_LEVEL = 32;
180
181 /***
182 * Mask value for indexing into segments
183 **/
184
185 protected static final int SEGMENT_MASK = CONCURRENCY_LEVEL - 1;
186
187 /***
188 * Bookkeeping for each concurrency control segment.
189 * Each segment contains a local count of the number of
190 * elements in its region.
191 * However, the main use of a Segment is for its lock.
192 **/
193 protected final static class Segment implements Serializable {
194 /***
195 * The number of elements in this segment's region.
196 * It is always updated within synchronized blocks.
197 **/
198 protected int count;
199
200 /***
201 * Get the count under synch.
202 **/
203 protected synchronized int getCount() { return count; }
204
205 /***
206 * Force a synchronization
207 **/
208 protected synchronized void synch() {}
209 }
210
211 /***
212 * The array of concurrency control segments.
213 **/
214
215 protected final Segment[] segments = new Segment[CONCURRENCY_LEVEL];
216
217
218 /***
219 * The default initial number of table slots for this table (32).
220 * Used when not otherwise specified in constructor.
221 **/
222 public static int DEFAULT_INITIAL_CAPACITY = 32;
223
224
225 /***
226 * The minimum capacity, used if a lower value is implicitly specified
227 * by either of the constructors with arguments.
228 * MUST be a power of two.
229 */
230 private static final int MINIMUM_CAPACITY = 32;
231
232 /***
233 * The maximum capacity, used if a higher value is implicitly specified
234 * by either of the constructors with arguments.
235 * MUST be a power of two <= 1<<30.
236 */
237 private static final int MAXIMUM_CAPACITY = 1 << 30;
238
239 /***
240 * The default load factor for this table (0.75)
241 * Used when not otherwise specified in constructor.
242 **/
243
244 public static final float DEFAULT_LOAD_FACTOR = 0.75f;
245
246 /***
247 * The load factor for the hash table.
248 *
249 * @serial
250 */
251 protected final float loadFactor;
252
253 /***
254 * Per-segment resize threshold.
255 *
256 * @serial
257 */
258 protected int threshold;
259
260
261 /***
262 * Number of segments voting for resize. The table is
263 * doubled when 1/4 of the segments reach threshold.
264 * Volatile but updated without synch since this is just a heuristic.
265 **/
266
267 protected transient volatile int votesForResize;
268
269
270 /***
271 * Return the number of set bits in w.
272 * For a derivation of this algorithm, see
273 * "Algorithms and data structures with applications to
274 * graphics and geometry", by Jurg Nievergelt and Klaus Hinrichs,
275 * Prentice Hall, 1993.
276 * See also notes by Torsten Sillke at
277 * http://www.mathematik.uni-bielefeld.de/~sillke/PROBLEMS/bitcount
278 **/
279 protected static int bitcount(int w) {
280 w -= (0xaaaaaaaa & w) >>> 1;
281 w = (w & 0x33333333) + ((w >>> 2) & 0x33333333);
282 w = (w + (w >>> 4)) & 0x0f0f0f0f;
283 w += w >>> 8;
284 w += w >>> 16;
285 return w & 0xff;
286 }
287
288 /***
289 * Returns the appropriate capacity (power of two) for the specified
290 * initial capacity argument.
291 */
292 private int p2capacity(int initialCapacity) {
293 int cap = initialCapacity;
294
295
296 int result;
297 if (cap > MAXIMUM_CAPACITY || cap < 0) {
298 result = MAXIMUM_CAPACITY;
299 } else {
300 result = MINIMUM_CAPACITY;
301 while (result < cap)
302 result <<= 1;
303 }
304 return result;
305 }
306
307 /***
308 * Return hash code for Object x. Since we are using power-of-two
309 * tables, it is worth the effort to improve hashcode via
310 * the same multiplicative scheme as used in IdentityHashMap.
311 */
312 protected static int hash(Object x) {
313 int h = x.hashCode();
314
315
316
317 return ((h << 7) - h + (h >>> 9) + (h >>> 17));
318 }
319
320
321 /***
322 * Check for equality of non-null references x and y.
323 **/
324 protected boolean eq(Object x, Object y) {
325 return x == y || x.equals(y);
326 }
327
328 /*** Create table array and set the per-segment threshold **/
329 protected Entry[] newTable(int capacity) {
330 threshold = (int)(capacity * loadFactor / CONCURRENCY_LEVEL) + 1;
331 return new Entry[capacity];
332 }
333
334 /***
335 * Constructs a new, empty map with the specified initial
336 * capacity and the specified load factor.
337 *
338 * @param initialCapacity the initial capacity.
339 * The actual initial capacity is rounded to the nearest power of two.
340 * @param loadFactor the load factor threshold, used to control resizing.
341 * This value is used in an approximate way: When at least
342 * a quarter of the segments of the table reach per-segment threshold, or
343 * one of the segments itself exceeds overall threshold,
344 * the table is doubled.
345 * This will on average cause resizing when the table-wide
346 * load factor is slightly less than the threshold. If you'd like
347 * to avoid resizing, you can set this to a ridiculously large
348 * value.
349 * @throws IllegalArgumentException if the load factor is nonpositive.
350 */
351 public ConcurrentHashMap(int initialCapacity,
352 float loadFactor) {
353 if (!(loadFactor > 0))
354 throw new IllegalArgumentException("Illegal Load factor: "+
355 loadFactor);
356 this.loadFactor = loadFactor;
357 for (int i = 0; i < segments.length; ++i)
358 segments[i] = new Segment();
359 int cap = p2capacity(initialCapacity);
360 table = newTable(cap);
361 }
362
363 /***
364 * Constructs a new, empty map with the specified initial
365 * capacity and default load factor.
366 *
367 * @param initialCapacity the initial capacity of the
368 * ConcurrentHashMap.
369 * @throws IllegalArgumentException if the initial maximum number
370 * of elements is less
371 * than zero.
372 */
373 public ConcurrentHashMap(int initialCapacity) {
374 this(initialCapacity, DEFAULT_LOAD_FACTOR);
375 }
376
377 /***
378 * Constructs a new, empty map with a default initial capacity
379 * and default load factor.
380 */
381 public ConcurrentHashMap() {
382 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
383 }
384
385 /***
386 * Constructs a new map with the same mappings as the given map. The
387 * map is created with a capacity of twice the number of mappings in
388 * the given map or 32 (whichever is greater), and a default load factor.
389 */
390 public ConcurrentHashMap(Map t) {
391 this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1,
392 MINIMUM_CAPACITY),
393 DEFAULT_LOAD_FACTOR);
394 putAll(t);
395 }
396
397 /***
398 * Returns the number of key-value mappings in this map.
399 *
400 * @return the number of key-value mappings in this map.
401 */
402 public int size() {
403 int c = 0;
404 for (int i = 0; i < segments.length; ++i)
405 c += segments[i].getCount();
406 return c;
407 }
408
409 /***
410 * Returns <tt>true</tt> if this map contains no key-value mappings.
411 *
412 * @return <tt>true</tt> if this map contains no key-value mappings.
413 */
414 public boolean isEmpty() {
415 for (int i = 0; i < segments.length; ++i)
416 if (segments[i].getCount() != 0)
417 return false;
418 return true;
419 }
420
421
422 /***
423 * Returns the value to which the specified key is mapped in this table.
424 *
425 * @param key a key in the table.
426 * @return the value to which the key is mapped in this table;
427 * <code>null</code> if the key is not mapped to any value in
428 * this table.
429 * @exception NullPointerException if the key is
430 * <code>null</code>.
431 * @see #put(Object, Object)
432 */
433 public Object get(Object key) {
434 int hash = hash(key);
435
436
437 Entry[] tab = table;
438 int index = hash & (tab.length - 1);
439 Entry first = tab[index];
440 Entry e;
441
442 for (e = first; e != null; e = e.next) {
443 if (e.hash == hash && eq(key, e.key)) {
444 Object value = e.value;
445 if (value != null)
446 return value;
447 else
448 break;
449 }
450 }
451
452
453 Segment seg = segments[hash & SEGMENT_MASK];
454 synchronized(seg) {
455 tab = table;
456 index = hash & (tab.length - 1);
457 Entry newFirst = tab[index];
458 if (e != null || first != newFirst) {
459 for (e = newFirst; e != null; e = e.next) {
460 if (e.hash == hash && eq(key, e.key))
461 return e.value;
462 }
463 }
464 return null;
465 }
466 }
467
468 /***
469 * Tests if the specified object is a key in this table.
470 *
471 * @param key possible key.
472 * @return <code>true</code> if and only if the specified object
473 * is a key in this table, as determined by the
474 * <tt>equals</tt> method; <code>false</code> otherwise.
475 * @exception NullPointerException if the key is
476 * <code>null</code>.
477 * @see #contains(Object)
478 */
479
480 public boolean containsKey(Object key) {
481 return get(key) != null;
482 }
483
484
485 /***
486 * Maps the specified <code>key</code> to the specified
487 * <code>value</code> in this table. Neither the key nor the
488 * value can be <code>null</code>. (Note that this policy is
489 * the same as for java.util.Hashtable, but unlike java.util.HashMap,
490 * which does accept nulls as valid keys and values.)<p>
491 *
492 * The value can be retrieved by calling the <code>get</code> method
493 * with a key that is equal to the original key.
494 *
495 * @param key the table key.
496 * @param value the value.
497 * @return the previous value of the specified key in this table,
498 * or <code>null</code> if it did not have one.
499 * @exception NullPointerException if the key or value is
500 * <code>null</code>.
501 * @see Object#equals(Object)
502 * @see #get(Object)
503 */
504 public Object put(Object key, Object value) {
505 if (value == null)
506 throw new NullPointerException();
507
508 int hash = hash(key);
509 Segment seg = segments[hash & SEGMENT_MASK];
510 int segcount;
511 Entry[] tab;
512 int votes;
513
514 synchronized(seg) {
515 tab = table;
516 int index = hash & (tab.length-1);
517 Entry first = tab[index];
518
519 for (Entry e = first; e != null; e = e.next) {
520 if (e.hash == hash && eq(key, e.key)) {
521 Object oldValue = e.value;
522 e.value = value;
523 return oldValue;
524 }
525 }
526
527
528 Entry newEntry = new Entry(hash, key, value, first);
529 tab[index] = newEntry;
530
531 if ((segcount = ++seg.count) < threshold)
532 return null;
533
534 int bit = (1 << (hash & SEGMENT_MASK));
535 votes = votesForResize;
536 if ((votes & bit) == 0)
537 votes = votesForResize |= bit;
538 }
539
540
541
542
543 if (bitcount(votes) >= CONCURRENCY_LEVEL / 4 ||
544 segcount > (threshold * CONCURRENCY_LEVEL))
545 resize(0, tab);
546
547 return null;
548 }
549
550 /***
551 * Gather all locks in order to call rehash, by
552 * recursing within synch blocks for each segment index.
553 * @param index the current segment. initially call value must be 0
554 * @param assumedTab the state of table on first call to resize. If
555 * this changes on any call, the attempt is aborted because the
556 * table has already been resized by another thread.
557 */
558
559 protected void resize(int index, Entry[] assumedTab) {
560 Segment seg = segments[index];
561 synchronized(seg) {
562 if (assumedTab == table) {
563 int next = index+1;
564 if (next < segments.length)
565 resize(next, assumedTab);
566 else
567 rehash();
568 }
569 }
570 }
571
572 /***
573 * Rehashes the contents of this map into a new table
574 * with a larger capacity.
575 */
576 protected void rehash() {
577 votesForResize = 0;
578
579 Entry[] oldTable = table;
580 int oldCapacity = oldTable.length;
581
582 if (oldCapacity >= MAXIMUM_CAPACITY) {
583 threshold = Integer.MAX_VALUE;
584 return;
585 }
586
587 int newCapacity = oldCapacity << 1;
588 Entry[] newTable = newTable(newCapacity);
589 int mask = newCapacity - 1;
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605 for (int i = 0; i < oldCapacity ; i++) {
606
607
608 Entry e = oldTable[i];
609
610 if (e != null) {
611 int idx = e.hash & mask;
612 Entry next = e.next;
613
614
615 if (next == null)
616 newTable[idx] = e;
617
618 else {
619
620 Entry lastRun = e;
621 int lastIdx = idx;
622 for (Entry last = next; last != null; last = last.next) {
623 int k = last.hash & mask;
624 if (k != lastIdx) {
625 lastIdx = k;
626 lastRun = last;
627 }
628 }
629 newTable[lastIdx] = lastRun;
630
631
632 for (Entry p = e; p != lastRun; p = p.next) {
633 int k = p.hash & mask;
634 newTable[k] = new Entry(p.hash, p.key,
635 p.value, newTable[k]);
636 }
637 }
638 }
639 }
640
641 table = newTable;
642 }
643
644
645 /***
646 * Removes the key (and its corresponding value) from this
647 * table. This method does nothing if the key is not in the table.
648 *
649 * @param key the key that needs to be removed.
650 * @return the value to which the key had been mapped in this table,
651 * or <code>null</code> if the key did not have a mapping.
652 * @exception NullPointerException if the key is
653 * <code>null</code>.
654 */
655 public Object remove(Object key) {
656 return remove(key, null);
657 }
658
659
660 /***
661 * Removes the (key, value) pair from this
662 * table. This method does nothing if the key is not in the table,
663 * or if the key is associated with a different value. This method
664 * is needed by EntrySet.
665 *
666 * @param key the key that needs to be removed.
667 * @param value the associated value. If the value is null,
668 * it means "any value".
669 * @return the value to which the key had been mapped in this table,
670 * or <code>null</code> if the key did not have a mapping.
671 * @exception NullPointerException if the key is
672 * <code>null</code>.
673 */
674
675 protected Object remove(Object key, Object value) {
676
677
678
679
680
681
682
683
684
685
686 int hash = hash(key);
687 Segment seg = segments[hash & SEGMENT_MASK];
688
689 synchronized(seg) {
690 Entry[] tab = table;
691 int index = hash & (tab.length-1);
692 Entry first = tab[index];
693 Entry e = first;
694
695 for (;;) {
696 if (e == null)
697 return null;
698 if (e.hash == hash && eq(key, e.key))
699 break;
700 e = e.next;
701 }
702
703 Object oldValue = e.value;
704 if (value != null && !value.equals(oldValue))
705 return null;
706
707 e.value = null;
708
709 Entry head = e.next;
710 for (Entry p = first; p != e; p = p.next)
711 head = new Entry(p.hash, p.key, p.value, head);
712 tab[index] = head;
713 seg.count--;
714 return oldValue;
715 }
716 }
717
718
719 /***
720 * Returns <tt>true</tt> if this map maps one or more keys to the
721 * specified value. Note: This method requires a full internal
722 * traversal of the hash table, and so is much slower than
723 * method <tt>containsKey</tt>.
724 *
725 * @param value value whose presence in this map is to be tested.
726 * @return <tt>true</tt> if this map maps one or more keys to the
727 * specified value.
728 * @exception NullPointerException if the value is <code>null</code>.
729 */
730 public boolean containsValue(Object value) {
731
732 if (value == null) throw new NullPointerException();
733
734 for (int s = 0; s < segments.length; ++s) {
735 Segment seg = segments[s];
736 Entry[] tab;
737 synchronized(seg) { tab = table; }
738 for (int i = s; i < tab.length; i+= segments.length) {
739 for (Entry e = tab[i]; e != null; e = e.next)
740 if (value.equals(e.value))
741 return true;
742 }
743 }
744 return false;
745 }
746
747 /***
748 * Tests if some key maps into the specified value in this table.
749 * This operation is more expensive than the <code>containsKey</code>
750 * method.<p>
751 *
752 * Note that this method is identical in functionality to containsValue,
753 * (which is part of the Map interface in the collections framework).
754 *
755 * @param value a value to search for.
756 * @return <code>true</code> if and only if some key maps to the
757 * <code>value</code> argument in this table as
758 * determined by the <tt>equals</tt> method;
759 * <code>false</code> otherwise.
760 * @exception NullPointerException if the value is <code>null</code>.
761 * @see #containsKey(Object)
762 * @see #containsValue(Object)
763 * @see Map
764 */
765
766 public boolean contains(Object value) {
767 return containsValue(value);
768 }
769
770 /***
771 * Copies all of the mappings from the specified map to this one.
772 *
773 * These mappings replace any mappings that this map had for any of the
774 * keys currently in the specified Map.
775 *
776 * @param t Mappings to be stored in this map.
777 */
778
779 public void putAll(Map t) {
780 int n = t.size();
781 if (n == 0)
782 return;
783
784
785
786
787 for(;;) {
788 Entry[] tab;
789 int max;
790 synchronized(segments[0]) {
791 tab = table;
792 max = threshold * CONCURRENCY_LEVEL;
793 }
794 if (n < max)
795 break;
796 resize(0, tab);
797 }
798
799 for (Iterator it = t.entrySet().iterator(); it.hasNext();) {
800 Map.Entry entry = (Map.Entry) it.next();
801 put(entry.getKey(), entry.getValue());
802 }
803 }
804
805 /***
806 * Removes all mappings from this map.
807 */
808
809 public void clear() {
810
811
812 for (int s = 0; s < segments.length; ++s) {
813 Segment seg = segments[s];
814 synchronized(seg) {
815 Entry[] tab = table;
816 for (int i = s; i < tab.length; i+= segments.length) {
817 for (Entry e = tab[i]; e != null; e = e.next)
818 e.value = null;
819 tab[i] = null;
820 seg.count = 0;
821 }
822 }
823 }
824 }
825
826 /***
827 * Returns a shallow copy of this
828 * <tt>ConcurrentHashMap</tt> instance: the keys and
829 * values themselves are not cloned.
830 *
831 * @return a shallow copy of this map.
832 */
833
834 public Object clone() {
835
836
837 return new ConcurrentHashMap(this);
838 }
839
840
841
842 protected transient Set keySet = null;
843 protected transient Set entrySet = null;
844 protected transient Collection values = null;
845
846 /***
847 * Returns a set view of the keys contained in this map. The set is
848 * backed by the map, so changes to the map are reflected in the set, and
849 * vice-versa. The set supports element removal, which removes the
850 * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
851 * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
852 * <tt>clear</tt> operations. It does not support the <tt>add</tt> or
853 * <tt>addAll</tt> operations.
854 *
855 * @return a set view of the keys contained in this map.
856 */
857
858 public Set keySet() {
859 Set ks = keySet;
860 return (ks != null)? ks : (keySet = new KeySet());
861 }
862
863 private class KeySet extends AbstractSet {
864 public Iterator iterator() {
865 return new KeyIterator();
866 }
867 public int size() {
868 return ConcurrentHashMap.this.size();
869 }
870 public boolean contains(Object o) {
871 return ConcurrentHashMap.this.containsKey(o);
872 }
873 public boolean remove(Object o) {
874 return ConcurrentHashMap.this.remove(o) != null;
875 }
876 public void clear() {
877 ConcurrentHashMap.this.clear();
878 }
879 }
880
881 /***
882 * Returns a collection view of the values contained in this map. The
883 * collection is backed by the map, so changes to the map are reflected in
884 * the collection, and vice-versa. The collection supports element
885 * removal, which removes the corresponding mapping from this map, via the
886 * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
887 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
888 * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
889 *
890 * @return a collection view of the values contained in this map.
891 */
892
893 public Collection values() {
894 Collection vs = values;
895 return (vs != null)? vs : (values = new Values());
896 }
897
898 private class Values extends AbstractCollection {
899 public Iterator iterator() {
900 return new ValueIterator();
901 }
902 public int size() {
903 return ConcurrentHashMap.this.size();
904 }
905 public boolean contains(Object o) {
906 return ConcurrentHashMap.this.containsValue(o);
907 }
908 public void clear() {
909 ConcurrentHashMap.this.clear();
910 }
911 }
912
913 /***
914 * Returns a collection view of the mappings contained in this map. Each
915 * element in the returned collection is a <tt>Map.Entry</tt>. The
916 * collection is backed by the map, so changes to the map are reflected in
917 * the collection, and vice-versa. The collection supports element
918 * removal, which removes the corresponding mapping from the map, via the
919 * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
920 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
921 * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
922 *
923 * @return a collection view of the mappings contained in this map.
924 */
925
926 public Set entrySet() {
927 Set es = entrySet;
928 return (es != null) ? es : (entrySet = new EntrySet());
929 }
930
931 private class EntrySet extends AbstractSet {
932 public Iterator iterator() {
933 return new HashIterator();
934 }
935 public boolean contains(Object o) {
936 if (!(o instanceof Map.Entry))
937 return false;
938 Map.Entry entry = (Map.Entry)o;
939 Object v = ConcurrentHashMap.this.get(entry.getKey());
940 return v != null && v.equals(entry.getValue());
941 }
942 public boolean remove(Object o) {
943 if (!(o instanceof Map.Entry))
944 return false;
945 Map.Entry e = (Map.Entry)o;
946 return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()) != null;
947 }
948 public int size() {
949 return ConcurrentHashMap.this.size();
950 }
951 public void clear() {
952 ConcurrentHashMap.this.clear();
953 }
954 }
955
956 /***
957 * Returns an enumeration of the keys in this table.
958 *
959 * @return an enumeration of the keys in this table.
960 * @see Enumeration
961 * @see #elements()
962 * @see #keySet()
963 * @see Map
964 */
965 public Enumeration keys() {
966 return new KeyIterator();
967 }
968
969 /***
970 * Returns an enumeration of the values in this table.
971 * Use the Enumeration methods on the returned object to fetch the elements
972 * sequentially.
973 *
974 * @return an enumeration of the values in this table.
975 * @see java.util.Enumeration
976 * @see #keys()
977 * @see #values()
978 * @see Map
979 */
980
981 public Enumeration elements() {
982 return new ValueIterator();
983 }
984
985 /***
986 * ConcurrentHashMap collision list entry.
987 */
988
989 protected static class Entry implements Map.Entry {
990
991
992
993
994
995
996
997 protected final Object key;
998 protected volatile Object value;
999 protected final int hash;
1000 protected final Entry next;
1001
1002 Entry(int hash, Object key, Object value, Entry next) {
1003 this.value = value;
1004 this.hash = hash;
1005 this.key = key;
1006 this.next = next;
1007 }
1008
1009
1010
1011 public Object getKey() {
1012 return key;
1013 }
1014
1015 /***
1016 * Get the value. Note: In an entrySet or entrySet.iterator,
1017 * unless you can guarantee lack of concurrent modification,
1018 * <tt>getValue</tt> <em>might</em> return null, reflecting the
1019 * fact that the entry has been concurrently removed. However,
1020 * there are no assurances that concurrent removals will be
1021 * reflected using this method.
1022 *
1023 * @return the current value, or null if the entry has been
1024 * detectably removed.
1025 **/
1026 public Object getValue() {
1027 return value;
1028 }
1029
1030 /***
1031 * Set the value of this entry. Note: In an entrySet or
1032 * entrySet.iterator), unless you can guarantee lack of concurrent
1033 * modification, <tt>setValue</tt> is not strictly guaranteed to
1034 * actually replace the value field obtained via the <tt>get</tt>
1035 * operation of the underlying hash table in multithreaded
1036 * applications. If iterator-wide synchronization is not used,
1037 * and any other concurrent <tt>put</tt> or <tt>remove</tt>
1038 * operations occur, sometimes even to <em>other</em> entries,
1039 * then this change is not guaranteed to be reflected in the hash
1040 * table. (It might, or it might not. There are no assurances
1041 * either way.)
1042 *
1043 * @param value the new value.
1044 * @return the previous value, or null if entry has been detectably
1045 * removed.
1046 * @exception NullPointerException if the value is <code>null</code>.
1047 *
1048 **/
1049
1050 public Object setValue(Object value) {
1051 if (value == null)
1052 throw new NullPointerException();
1053 Object oldValue = this.value;
1054 this.value = value;
1055 return oldValue;
1056 }
1057
1058 public boolean equals(Object o) {
1059 if (!(o instanceof Map.Entry))
1060 return false;
1061 Map.Entry e = (Map.Entry)o;
1062 return (key.equals(e.getKey()) && value.equals(e.getValue()));
1063 }
1064
1065 public int hashCode() {
1066 return key.hashCode() ^ value.hashCode();
1067 }
1068
1069 public String toString() {
1070 return key + "=" + value;
1071 }
1072
1073 }
1074
1075 protected class HashIterator implements Iterator, Enumeration {
1076 protected final Entry[] tab;
1077 protected int index;
1078 protected Entry entry = null;
1079 protected Object currentKey;
1080 protected Object currentValue;
1081 protected Entry lastReturned = null;
1082
1083 protected HashIterator() {
1084
1085 synchronized(segments[0]) { tab = table; }
1086 for (int i = 1; i < segments.length; ++i) segments[i].synch();
1087 index = tab.length - 1;
1088 }
1089
1090 public boolean hasMoreElements() { return hasNext(); }
1091 public Object nextElement() { return next(); }
1092
1093 public boolean hasNext() {
1094
1095
1096
1097
1098
1099
1100
1101
1102 for (;;) {
1103 if (entry != null) {
1104 Object v = entry.value;
1105 if (v != null) {
1106 currentKey = entry.key;
1107 currentValue = v;
1108 return true;
1109 }
1110 else
1111 entry = entry.next;
1112 }
1113
1114 while (entry == null && index >= 0)
1115 entry = tab[index--];
1116
1117 if (entry == null) {
1118 currentKey = currentValue = null;
1119 return false;
1120 }
1121 }
1122 }
1123
1124 protected Object returnValueOfNext() { return entry; }
1125
1126 public Object next() {
1127 if (currentKey == null && !hasNext())
1128 throw new NoSuchElementException();
1129
1130 Object result = returnValueOfNext();
1131 lastReturned = entry;
1132 currentKey = currentValue = null;
1133 entry = entry.next;
1134 return result;
1135 }
1136
1137 public void remove() {
1138 if (lastReturned == null)
1139 throw new IllegalStateException();
1140 ConcurrentHashMap.this.remove(lastReturned.key);
1141 lastReturned = null;
1142 }
1143
1144 }
1145
1146 protected class KeyIterator extends HashIterator {
1147 protected Object returnValueOfNext() { return currentKey; }
1148 }
1149
1150 protected class ValueIterator extends HashIterator {
1151 protected Object returnValueOfNext() { return currentValue; }
1152 }
1153
1154 /***
1155 * Save the state of the <tt>ConcurrentHashMap</tt>
1156 * instance to a stream (i.e.,
1157 * serialize it).
1158 *
1159 * @serialData
1160 * An estimate of the table size, followed by
1161 * the key (Object) and value (Object)
1162 * for each key-value mapping, followed by a null pair.
1163 * The key-value mappings are emitted in no particular order.
1164 */
1165
1166 private void writeObject(java.io.ObjectOutputStream s)
1167 throws IOException {
1168
1169 s.defaultWriteObject();
1170
1171
1172
1173
1174
1175 int cap;
1176 synchronized(segments[0]) { cap = table.length; }
1177 s.writeInt(cap);
1178
1179
1180 for (int k = 0; k < segments.length; ++k) {
1181 Segment seg = segments[k];
1182 Entry[] tab;
1183 synchronized(seg) { tab = table; }
1184 for (int i = k; i < tab.length; i+= segments.length) {
1185 for (Entry e = tab[i]; e != null; e = e.next) {
1186 s.writeObject(e.key);
1187 s.writeObject(e.value);
1188 }
1189 }
1190 }
1191
1192 s.writeObject(null);
1193 s.writeObject(null);
1194 }
1195
1196 /***
1197 * Reconstitute the <tt>ConcurrentHashMap</tt>
1198 * instance from a stream (i.e.,
1199 * deserialize it).
1200 */
1201 private void readObject(java.io.ObjectInputStream s)
1202 throws IOException, ClassNotFoundException {
1203
1204 s.defaultReadObject();
1205
1206 int cap = s.readInt();
1207 table = newTable(cap);
1208 for (int i = 0; i < segments.length; ++i)
1209 segments[i] = new Segment();
1210
1211
1212
1213 for (;;) {
1214 Object key = s.readObject();
1215 Object value = s.readObject();
1216 if (key == null)
1217 break;
1218 put(key, value);
1219 }
1220 }
1221 }