ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentHashMap.java
Revision: 1.8
Committed: Tue Jun 24 14:34:47 2003 UTC (20 years, 11 months ago) by dl
Branch: MAIN
Changes since 1.7: +35 -25 lines
Log Message:
Added missing javadoc tags; minor reformatting

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. Use, modify, and
4 * redistribute this code in any way without acknowledgement.
5 */
6
7 package java.util.concurrent;
8
9 import java.util.*;
10 import java.io.Serializable;
11 import java.io.IOException;
12 import java.io.ObjectInputStream;
13 import java.io.ObjectOutputStream;
14
15 /**
16 * A hash table supporting full concurrency of retrievals and
17 * adjustable expected concurrency for updates. This class obeys the
18 * same functional specification as
19 * <tt>java.util.Hashtable</tt>. However, even though all operations
20 * are thread-safe, retrieval operations do <em>not</em> entail
21 * locking, and there is <em>not</em> any support for locking the
22 * entire table in a way that prevents all access. This class is
23 * fully interoperable with Hashtable in programs that rely on its
24 * thread safety but not on its synchronization details.
25 *
26 * <p> Retrieval operations (including <tt>get</tt>) ordinarily
27 * overlap with update operations (including <tt>put</tt> and
28 * <tt>remove</tt>). Retrievals reflect the results of the most
29 * recently <em>completed</em> update operations holding upon their
30 * onset. For aggregate operations such as <tt>putAll</tt> and
31 * <tt>clear</tt>, concurrent retrievals may reflect insertion or
32 * removal of only some entries. Similarly, Iterators and
33 * Enumerations return elements reflecting the state of the hash table
34 * at some point at or since the creation of the iterator/enumeration.
35 * They do <em>not</em> throw ConcurrentModificationException.
36 * However, Iterators are designed to be used by only one thread at a
37 * time.
38 *
39 * <p> The allowed concurrency among update operations is controlled
40 * by the optional <tt>segments</tt> constructor argument (default
41 * 16). The table is divided into this many independent parts, each of
42 * which can be updated concurrently. Because placement in hash tables
43 * is essentially random, the actual concurrency will vary. As a rough
44 * rule of thumb, you should choose at least as many segments as you
45 * expect concurrent threads. However, using more segments than you
46 * need can waste space and time. Using a value of 1 for
47 * <tt>segments</tt> results in a table that is concurrently readable
48 * but can only be updated by one thread at a time.
49 *
50 * <p> Like Hashtable but unlike java.util.HashMap, this class does
51 * NOT allow <tt>null</tt> to be used as a key or value.
52 *
53 * @since 1.5
54 * @author Doug Lea
55 */
56 public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
57 implements ConcurrentMap<K, V>, Cloneable, Serializable {
58
59 /*
60 * The basic strategy is to subdivide the table among Segments,
61 * each of which itself is a concurrently readable hash table.
62 */
63
64 /* ---------------- Constants -------------- */
65
66 /**
67 * The default initial number of table slots for this table (32).
68 * Used when not otherwise specified in constructor.
69 */
70 private static int DEFAULT_INITIAL_CAPACITY = 16;
71
72 /**
73 * The maximum capacity, used if a higher value is implicitly
74 * specified by either of the constructors with arguments. MUST
75 * be a power of two <= 1<<30.
76 */
77 static final int MAXIMUM_CAPACITY = 1 << 30;
78
79 /**
80 * The default load factor for this table. Used when not
81 * otherwise specified in constructor.
82 */
83 static final float DEFAULT_LOAD_FACTOR = 0.75f;
84
85 /**
86 * The default number of concurrency control segments.
87 **/
88 private static final int DEFAULT_SEGMENTS = 16;
89
90 /* ---------------- Fields -------------- */
91
92 /**
93 * Mask value for indexing into segments. The lower bits of a
94 * key's hash code are used to choose the segment, and the
95 * remaining bits are used as the placement hashcode used within
96 * the segment.
97 **/
98 private final int segmentMask;
99
100 /**
101 * Shift value for indexing within segments.
102 **/
103 private final int segmentShift;
104
105 /**
106 * The segments, each of which is a specialized hash table
107 */
108 private final Segment<K,V>[] segments;
109
110 private transient Set<K> keySet;
111 private transient Set/*<Map.Entry<K,V>>*/ entrySet;
112 private transient Collection<V> values;
113
114 /* ---------------- Small Utilities -------------- */
115
116 /**
117 * Return a hash code for non-null Object x.
118 * Uses the same hash code spreader as most other j.u hash tables.
119 * @param x the object serving as a key
120 * @return the hash code
121 */
122 private static int hash(Object x) {
123 int h = x.hashCode();
124 h += ~(h << 9);
125 h ^= (h >>> 14);
126 h += (h << 4);
127 h ^= (h >>> 10);
128 return h;
129 }
130
131 /**
132 * Check for equality of non-null references x and y.
133 **/
134 private static boolean eq(Object x, Object y) {
135 return x == y || x.equals(y);
136 }
137
138 /**
139 * Return index for hash code h in table of given length.
140 */
141 private static int indexFor(int h, int length) {
142 return h & (length-1);
143 }
144
145 /**
146 * Return the segment that should be used for key with given hash
147 */
148 private Segment<K,V> segmentFor(int hash) {
149 return segments[hash & segmentMask];
150 }
151
152 /**
153 * Strip the segment index from hash code to use as a per-segment hash.
154 */
155 private int segmentHashFor(int hash) {
156 return hash >>> segmentShift;
157 }
158
159 /* ---------------- Inner Classes -------------- */
160
161 /**
162 * Segments are specialized versions of hash tables. This
163 * subclasses from ReentrantLock opportunistically, just to
164 * simplify some locking and avoid separate construction.
165 **/
166 private static final class Segment<K,V> extends ReentrantLock implements Serializable {
167 /*
168 * Segments maintain a table of entry lists that are ALWAYS
169 * kept in a consistent state, so can be read without locking.
170 * Next fields of nodes are immutable (final). All list
171 * additions are performed at the front of each bin. This
172 * makes it easy to check changes, and also fast to traverse.
173 * When nodes would otherwise be changed, new nodes are
174 * created to replace them. This works well for hash tables
175 * since the bin lists tend to be short. (The average length
176 * is less than two for the default load factor threshold.)
177 *
178 * Read operations can thus proceed without locking, but rely
179 * on a memory barrier to ensure that completed write
180 * operations performed by other threads are
181 * noticed. Conveniently, the "count" field, tracking the
182 * number of elements, can also serve as the volatile variable
183 * providing proper read/write barriers. This is convenient
184 * because this field needs to be read in many read operations
185 * anyway. The use of volatiles for this purpose is only
186 * guaranteed to work in accord with reuirements in
187 * multithreaded environments when run on JVMs conforming to
188 * the clarified JSR133 memory model specification. This true
189 * for hotspot as of release 1.4.
190 *
191 * Implementors note. The basic rules for all this are:
192 *
193 * - All unsynchronized read operations must first read the
194 * "count" field, and should not look at table entries if
195 * it is 0.
196 *
197 * - All synchronized write operations should write to
198 * the "count" field after updating. The operations must not
199 * take any action that could even momentarily cause
200 * a concurrent read operation to see inconsistent
201 * data. This is made easier by the nature of the read
202 * operations in Map. For example, no operation
203 * can reveal that the table has grown but the threshold
204 * has not yet been updated, so there are no atomicity
205 * requirements for this with respect to reads.
206 *
207 * As a guide, all critical volatile reads and writes are marked
208 * in code comments.
209 */
210
211 /**
212 * The number of elements in this segment's region.
213 **/
214 transient volatile int count;
215
216 /**
217 * The table is rehashed when its size exceeds this threshold.
218 * (The value of this field is always (int)(capacity *
219 * loadFactor).)
220 */
221 private transient int threshold;
222
223 /**
224 * The per-segment table
225 */
226 transient HashEntry<K,V>[] table;
227
228 /**
229 * The load factor for the hash table. Even though this value
230 * is same for all segments, it is replicated to avoid needing
231 * links to outer object.
232 * @serial
233 */
234 private final float loadFactor;
235
236 Segment(int initialCapacity, float lf) {
237 loadFactor = lf;
238 setTable(new HashEntry<K,V>[initialCapacity]);
239 }
240
241 /**
242 * Set table to new HashEntry array.
243 * Call only while holding lock or in constructor.
244 **/
245 private void setTable(HashEntry<K,V>[] newTable) {
246 table = newTable;
247 threshold = (int)(newTable.length * loadFactor);
248 count = count; // write-volatile
249 }
250
251 /* Specialized implementations of map methods */
252
253 V get(K key, int hash) {
254 if (count != 0) { // read-volatile
255 HashEntry<K,V>[] tab = table;
256 int index = indexFor(hash, tab.length);
257 HashEntry<K,V> e = tab[index];
258 while (e != null) {
259 if (e.hash == hash && eq(key, e.key))
260 return e.value;
261 e = e.next;
262 }
263 }
264 return null;
265 }
266
267 boolean containsKey(Object key, int hash) {
268 if (count != 0) { // read-volatile
269 HashEntry<K,V>[] tab = table;
270 int index = indexFor(hash, tab.length);
271 HashEntry<K,V> e = tab[index];
272 while (e != null) {
273 if (e.hash == hash && eq(key, e.key))
274 return true;
275 e = e.next;
276 }
277 }
278 return false;
279 }
280
281 boolean containsValue(Object value) {
282 if (count != 0) { // read-volatile
283 HashEntry<K,V> tab[] = table;
284 int len = tab.length;
285 for (int i = 0 ; i < len; i++)
286 for (HashEntry<K,V> e = tab[i] ; e != null ; e = e.next)
287 if (value.equals(e.value))
288 return true;
289 }
290 return false;
291 }
292
293 V put(K key, int hash, V value, boolean onlyIfAbsent) {
294 lock();
295 try {
296 HashEntry<K,V>[] tab = table;
297 int index = indexFor(hash, tab.length);
298 HashEntry<K,V> first = tab[index];
299
300 for (HashEntry<K,V> e = first; e != null; e = e.next) {
301 if (e.hash == hash && eq(key, e.key)) {
302 V oldValue = e.value;
303 if (!onlyIfAbsent)
304 e.value = value;
305 count = count; // write-volatile
306 return oldValue;
307 }
308 }
309
310 tab[index] = new HashEntry<K,V>(hash, key, value, first);
311 if (++count > threshold) // write-volatile
312 rehash();
313 return null;
314 }
315 finally {
316 unlock();
317 }
318 }
319
320 private void rehash() {
321 HashEntry<K,V>[] oldTable = table;
322 int oldCapacity = oldTable.length;
323 if (oldCapacity >= MAXIMUM_CAPACITY)
324 return;
325
326 /*
327 * Reclassify nodes in each list to new Map. Because we are
328 * using power-of-two expansion, the elements from each bin
329 * must either stay at same index, or move with a power of two
330 * offset. We eliminate unnecessary node creation by catching
331 * cases where old nodes can be reused because their next
332 * fields won't change. Statistically, at the default
333 * threshhold, only about one-sixth of them need cloning when
334 * a table doubles. The nodes they replace will be garbage
335 * collectable as soon as they are no longer referenced by any
336 * reader thread that may be in the midst of traversing table
337 * right now.
338 */
339
340 HashEntry<K,V>[] newTable = new HashEntry<K,V>[oldCapacity << 1];
341 int sizeMask = newTable.length - 1;
342 for (int i = 0; i < oldCapacity ; i++) {
343 // We need to guarantee that any existing reads of old Map can
344 // proceed. So we cannot yet null out each bin.
345 HashEntry<K,V> e = oldTable[i];
346
347 if (e != null) {
348 HashEntry<K,V> next = e.next;
349 int idx = e.hash & sizeMask;
350
351 // Single node on list
352 if (next == null)
353 newTable[idx] = e;
354
355 else {
356 // Reuse trailing consecutive sequence at same slot
357 HashEntry<K,V> lastRun = e;
358 int lastIdx = idx;
359 for (HashEntry<K,V> last = next;
360 last != null;
361 last = last.next) {
362 int k = last.hash & sizeMask;
363 if (k != lastIdx) {
364 lastIdx = k;
365 lastRun = last;
366 }
367 }
368 newTable[lastIdx] = lastRun;
369
370 // Clone all remaining nodes
371 for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
372 int k = p.hash & sizeMask;
373 newTable[k] = new HashEntry<K,V>(p.hash,
374 p.key,
375 p.value,
376 newTable[k]);
377 }
378 }
379 }
380 }
381 setTable(newTable);
382 }
383
384 /**
385 * Remove; match on key only if value null, else match both.
386 */
387 V remove(Object key, int hash, Object value) {
388 lock();
389 try {
390 HashEntry[] tab = table;
391 int index = indexFor(hash, tab.length);
392 HashEntry<K,V> first = tab[index];
393
394 HashEntry<K,V> e = first;
395 while (true) {
396 if (e == null)
397 return null;
398 if (e.hash == hash && eq(key, e.key))
399 break;
400 e = e.next;
401 }
402
403 V oldValue = e.value;
404 if (value != null && !value.equals(oldValue))
405 return null;
406
407 // All entries following removed node can stay in list, but
408 // all preceeding ones need to be cloned.
409 HashEntry<K,V> newFirst = e.next;
410 for (HashEntry<K,V> p = first; p != e; p = p.next)
411 newFirst = new HashEntry<K,V>(p.hash, p.key,
412 p.value, newFirst);
413 tab[index] = newFirst;
414
415 count--; // write-volatile
416 return e.value;
417 }
418 finally {
419 unlock();
420 }
421 }
422
423 void clear() {
424 lock();
425 try {
426 HashEntry<K,V> tab[] = table;
427 for (int i = 0; i < tab.length ; i++)
428 tab[i] = null;
429 count = 0; // write-volatile
430 }
431 finally {
432 unlock();
433 }
434 }
435 }
436
437 /**
438 * ConcurrentReaderHashMap list entry.
439 */
440 private static class HashEntry<K,V> implements Entry<K,V> {
441 private final K key;
442 private V value;
443 private final int hash;
444 private final HashEntry<K,V> next;
445
446 HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
447 this.value = value;
448 this.hash = hash;
449 this.key = key;
450 this.next = next;
451 }
452
453 public K getKey() {
454 return key;
455 }
456
457 public V getValue() {
458 return value;
459 }
460
461 public V setValue(V newValue) {
462 // We aren't required to, and don't provide any
463 // visibility barriers for setting value.
464 if (newValue == null)
465 throw new NullPointerException();
466 V oldValue = this.value;
467 this.value = newValue;
468 return oldValue;
469 }
470
471 public boolean equals(Object o) {
472 if (!(o instanceof Entry))
473 return false;
474 Entry<K,V> e = (Entry)o;
475 return (key.equals(e.getKey()) && value.equals(e.getValue()));
476 }
477
478 public int hashCode() {
479 return key.hashCode() ^ value.hashCode();
480 }
481
482 public String toString() {
483 return key + "=" + value;
484 }
485 }
486
487
488 /* ---------------- Public operations -------------- */
489
490 /**
491 * Constructs a new, empty map with the specified initial
492 * capacity and the specified load factor.
493 *
494 * @param initialCapacity the initial capacity. The actual
495 * initial capacity is rounded up to the nearest power of two.
496 * @param loadFactor the load factor threshold, used to control resizing.
497 * @param segments the number of concurrently accessible segments. the
498 * actual number of segments is rounded to the next power of two.
499 * @throws IllegalArgumentException if the initial capacity is
500 * negative or the load factor or number of segments are
501 * nonpositive.
502 */
503 public ConcurrentHashMap(int initialCapacity,
504 float loadFactor, int segments) {
505 if (!(loadFactor > 0) || initialCapacity < 0 || segments <= 0)
506 throw new IllegalArgumentException();
507
508 // Find power-of-two sizes best matching arguments
509 int sshift = 0;
510 int ssize = 1;
511 while (ssize < segments) {
512 ++sshift;
513 ssize <<= 1;
514 }
515 segmentShift = sshift;
516 segmentMask = ssize - 1;
517 this.segments = new Segment<K,V>[ssize];
518
519 if (initialCapacity > MAXIMUM_CAPACITY)
520 initialCapacity = MAXIMUM_CAPACITY;
521 int c = initialCapacity / ssize;
522 if (c * ssize < initialCapacity)
523 ++c;
524 int cap = 1;
525 while (cap < c)
526 cap <<= 1;
527
528 for (int i = 0; i < this.segments.length; ++i)
529 this.segments[i] = new Segment<K,V>(cap, loadFactor);
530 }
531
532 /**
533 * Constructs a new, empty map with the specified initial
534 * capacity, and with default load factor and segments.
535 *
536 * @param initialCapacity the initial capacity of the
537 * ConcurrentHashMap.
538 * @throws IllegalArgumentException if the initial capacity of
539 * elements is negative.
540 */
541 public ConcurrentHashMap(int initialCapacity) {
542 this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
543 }
544
545 /**
546 * Constructs a new, empty map with a default initial capacity,
547 * load factor, and number of segments
548 */
549 public ConcurrentHashMap() {
550 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
551 }
552
553 /**
554 * Constructs a new map with the same mappings as the given map. The
555 * map is created with a capacity of twice the number of mappings in
556 * the given map or 11 (whichever is greater), and a default load factor.
557 */
558 public <A extends K, B extends V> ConcurrentHashMap(Map<A,B> t) {
559 this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1,
560 11),
561 DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
562 putAll(t);
563 }
564
565 // inherit Map javadoc
566 public int size() {
567 int c = 0;
568 for (int i = 0; i < segments.length; ++i)
569 c += segments[i].count;
570 return c;
571 }
572
573 // inherit Map javadoc
574 public boolean isEmpty() {
575 for (int i = 0; i < segments.length; ++i)
576 if (segments[i].count != 0)
577 return false;
578 return true;
579 }
580
581 /**
582 * Returns the value to which the specified key is mapped in this table.
583 *
584 * @param key a key in the table.
585 * @return the value to which the key is mapped in this table;
586 * <code>null</code> if the key is not mapped to any value in
587 * this table.
588 * @throws NullPointerException if the key is
589 * <code>null</code>.
590 * @see #put(Object, Object)
591 */
592 public V get(K key) {
593 int hash = hash(key); // throws NullPointerException if key null
594 return segmentFor(hash).get(key, segmentHashFor(hash));
595 }
596
597 /**
598 * Tests if the specified object is a key in this table.
599 *
600 * @param key possible key.
601 * @return <code>true</code> if and only if the specified object
602 * is a key in this table, as determined by the
603 * <tt>equals</tt> method; <code>false</code> otherwise.
604 * @throws NullPointerException if the key is
605 * <code>null</code>.
606 * @see #contains(Object)
607 */
608 public boolean containsKey(Object key) {
609 int hash = hash(key); // throws NullPointerException if key null
610 return segmentFor(hash).containsKey(key, segmentHashFor(hash));
611 }
612
613 /**
614 * Returns <tt>true</tt> if this map maps one or more keys to the
615 * specified value. Note: This method requires a full internal
616 * traversal of the hash table, and so is much slower than
617 * method <tt>containsKey</tt>.
618 *
619 * @param value value whose presence in this map is to be tested.
620 * @return <tt>true</tt> if this map maps one or more keys to the
621 * specified value.
622 * @throws NullPointerException if the value is <code>null</code>.
623 */
624 public boolean containsValue(Object value) {
625 if (value == null)
626 throw new NullPointerException();
627
628 for (int i = 0; i < segments.length; ++i) {
629 if (segments[i].containsValue(value))
630 return true;
631 }
632 return false;
633 }
634 /**
635 * Tests if some key maps into the specified value in this table.
636 * This operation is more expensive than the <code>containsKey</code>
637 * method.<p>
638 *
639 * Note that this method is identical in functionality to containsValue,
640 * (which is part of the Map interface in the collections framework).
641 *
642 * @param value a value to search for.
643 * @return <code>true</code> if and only if some key maps to the
644 * <code>value</code> argument in this table as
645 * determined by the <tt>equals</tt> method;
646 * <code>false</code> otherwise.
647 * @throws NullPointerException if the value is <code>null</code>.
648 * @see #containsKey(Object)
649 * @see #containsValue(Object)
650 * @see Map
651 */
652 public boolean contains(Object value) {
653 return containsValue(value);
654 }
655
656 /**
657 * Maps the specified <code>key</code> to the specified
658 * <code>value</code> in this table. Neither the key nor the
659 * value can be <code>null</code>. <p>
660 *
661 * The value can be retrieved by calling the <code>get</code> method
662 * with a key that is equal to the original key.
663 *
664 * @param key the table key.
665 * @param value the value.
666 * @return the previous value of the specified key in this table,
667 * or <code>null</code> if it did not have one.
668 * @throws NullPointerException if the key or value is
669 * <code>null</code>.
670 * @see Object#equals(Object)
671 * @see #get(Object)
672 */
673 public V put(K key, V value) {
674 if (value == null)
675 throw new NullPointerException();
676 int hash = hash(key);
677 return segmentFor(hash).put(key, segmentHashFor(hash), value, false);
678 }
679
680 /**
681 * If the specified key is not already associated
682 * with a value, associate it with the given value.
683 * This is equivalent to
684 * <pre>
685 * if (!map.containsKey(key)) map.put(key, value);
686 * return get(key);
687 * </pre>
688 * Except that the action is performed atomically.
689 * @param key key with which the specified value is to be associated.
690 * @param value value to be associated with the specified key.
691 * @return previous value associated with specified key, or <tt>null</tt>
692 * if there was no mapping for key. A <tt>null</tt> return can
693 * also indicate that the map previously associated <tt>null</tt>
694 * with the specified key, if the implementation supports
695 * <tt>null</tt> values.
696 *
697 * @throws NullPointerException this map does not permit <tt>null</tt>
698 * keys or values, and the specified key or value is
699 * <tt>null</tt>.
700 *
701 **/
702 public V putIfAbsent(K key, V value) {
703 if (value == null)
704 throw new NullPointerException();
705 int hash = hash(key);
706 return segmentFor(hash).put(key, segmentHashFor(hash), value, true);
707 }
708
709
710 /**
711 * Copies all of the mappings from the specified map to this one.
712 *
713 * These mappings replace any mappings that this map had for any of the
714 * keys currently in the specified Map.
715 *
716 * @param t Mappings to be stored in this map.
717 */
718 public <K1 extends K, V1 extends V> void putAll(Map<K1,V1> t) {
719 Iterator<Map.Entry<K1,V1>> it = t.entrySet().iterator();
720 while (it.hasNext()) {
721 Entry<K,V> e = (Entry) it.next();
722 put(e.getKey(), e.getValue());
723 }
724 }
725
726 /**
727 * Removes the key (and its corresponding value) from this
728 * table. This method does nothing if the key is not in the table.
729 *
730 * @param key the key that needs to be removed.
731 * @return the value to which the key had been mapped in this table,
732 * or <code>null</code> if the key did not have a mapping.
733 * @throws NullPointerException if the key is
734 * <code>null</code>.
735 */
736 public V remove(Object key) {
737 int hash = hash(key);
738 return segmentFor(hash).remove(key, segmentHashFor(hash), null);
739 }
740
741 /**
742 * Removes the (key, value) pair from this
743 * table. This method does nothing if the key is not in the table,
744 * or if the key is associated with a different value.
745 *
746 * @param key the key that needs to be removed.
747 * @param value the associated value. If the value is null,
748 * it means "any value".
749 * @return the value to which the key had been mapped in this table,
750 * or <code>null</code> if the key did not have a mapping.
751 * @throws NullPointerException if the key is
752 * <code>null</code>.
753 */
754 public V remove(Object key, Object value) {
755 int hash = hash(key);
756 return segmentFor(hash).remove(key, segmentHashFor(hash), value);
757 }
758
759 /**
760 * Removes all mappings from this map.
761 */
762 public void clear() {
763 for (int i = 0; i < segments.length; ++i)
764 segments[i].clear();
765 }
766
767
768 /**
769 * Returns a shallow copy of this
770 * <tt>ConcurrentHashMap</tt> instance: the keys and
771 * values themselves are not cloned.
772 *
773 * @return a shallow copy of this map.
774 */
775 public Object clone() {
776 // We cannot call super.clone, since it would share final
777 // segments array, and there's no way to reassign finals.
778
779 float lf = segments[0].loadFactor;
780 int segs = segments.length;
781 int cap = (int)(size() / lf);
782 if (cap < segs) cap = segs;
783 ConcurrentHashMap t = new ConcurrentHashMap(cap, lf, segs);
784 t.putAll(this);
785 return t;
786 }
787
788 /**
789 * Returns a set view of the keys contained in this map. The set is
790 * backed by the map, so changes to the map are reflected in the set, and
791 * vice-versa. The set supports element removal, which removes the
792 * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
793 * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
794 * <tt>clear</tt> operations. It does not support the <tt>add</tt> or
795 * <tt>addAll</tt> operations.
796 *
797 * @return a set view of the keys contained in this map.
798 */
799 public Set<K> keySet() {
800 Set<K> ks = keySet;
801 return (ks != null) ? ks : (keySet = new KeySet());
802 }
803
804
805 /**
806 * Returns a collection view of the values contained in this map. The
807 * collection is backed by the map, so changes to the map are reflected in
808 * the collection, and vice-versa. The collection supports element
809 * removal, which removes the corresponding mapping from this map, via the
810 * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
811 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
812 * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
813 *
814 * @return a collection view of the values contained in this map.
815 */
816 public Collection<V> values() {
817 Collection<V> vs = values;
818 return (vs != null) ? vs : (values = new Values());
819 }
820
821
822 /**
823 * Returns a collection view of the mappings contained in this map. Each
824 * element in the returned collection is a <tt>Map.Entry</tt>. The
825 * collection is backed by the map, so changes to the map are reflected in
826 * the collection, and vice-versa. The collection supports element
827 * removal, which removes the corresponding mapping from the map, via the
828 * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
829 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
830 * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
831 *
832 * @return a collection view of the mappings contained in this map.
833 */
834 public Set<Map.Entry<K,V>> entrySet() {
835 Set<Map.Entry<K,V>> es = entrySet;
836 return (es != null) ? es : (entrySet = new EntrySet());
837 }
838
839
840 /**
841 * Returns an enumeration of the keys in this table.
842 *
843 * @return an enumeration of the keys in this table.
844 * @see Enumeration
845 * @see #elements()
846 * @see #keySet()
847 * @see Map
848 */
849 public Enumeration<K> keys() {
850 return new KeyIterator();
851 }
852
853 /**
854 * Returns an enumeration of the values in this table.
855 * Use the Enumeration methods on the returned object to fetch the elements
856 * sequentially.
857 *
858 * @return an enumeration of the values in this table.
859 * @see java.util.Enumeration
860 * @see #keys()
861 * @see #values()
862 * @see Map
863 */
864 public Enumeration<V> elements() {
865 return new ValueIterator();
866 }
867
868 /* ---------------- Iterator Support -------------- */
869
870 private abstract class HashIterator {
871 private int nextSegmentIndex;
872 private int nextTableIndex;
873 private HashEntry<K, V>[] currentTable;
874 private HashEntry<K, V> nextEntry;
875 private HashEntry<K, V> lastReturned;
876
877 private HashIterator() {
878 nextSegmentIndex = segments.length - 1;
879 nextTableIndex = -1;
880 advance();
881 }
882
883 public boolean hasMoreElements() { return hasNext(); }
884
885 private void advance() {
886 if (nextEntry != null && (nextEntry = nextEntry.next) != null)
887 return;
888
889 while (nextTableIndex >= 0) {
890 if ( (nextEntry = currentTable[nextTableIndex--]) != null)
891 return;
892 }
893
894 while (nextSegmentIndex >= 0) {
895 Segment<K,V> seg = segments[nextSegmentIndex--];
896 if (seg.count != 0) {
897 currentTable = seg.table;
898 for (int j = currentTable.length - 1; j >= 0; --j) {
899 if ( (nextEntry = currentTable[j]) != null) {
900 nextTableIndex = j - 1;
901 return;
902 }
903 }
904 }
905 }
906 }
907
908 public boolean hasNext() { return nextEntry != null; }
909
910 HashEntry<K,V> nextEntry() {
911 if (nextEntry == null)
912 throw new NoSuchElementException();
913 lastReturned = nextEntry;
914 advance();
915 return lastReturned;
916 }
917
918 public void remove() {
919 if (lastReturned == null)
920 throw new IllegalStateException();
921 ConcurrentHashMap.this.remove(lastReturned.key);
922 lastReturned = null;
923 }
924 }
925
926 private class KeyIterator extends HashIterator implements Iterator<K>, Enumeration<K> {
927 public K next() { return super.nextEntry().key; }
928 public K nextElement() { return super.nextEntry().key; }
929 }
930
931 private class ValueIterator extends HashIterator implements Iterator<V>, Enumeration<V> {
932 public V next() { return super.nextEntry().value; }
933 public V nextElement() { return super.nextEntry().value; }
934 }
935
936 private class EntryIterator extends HashIterator implements Iterator<Entry<K,V>> {
937 public Map.Entry<K,V> next() { return super.nextEntry(); }
938 }
939
940 private class KeySet extends AbstractSet<K> {
941 public Iterator<K> iterator() {
942 return new KeyIterator();
943 }
944 public int size() {
945 return ConcurrentHashMap.this.size();
946 }
947 public boolean contains(Object o) {
948 return ConcurrentHashMap.this.containsKey(o);
949 }
950 public boolean remove(Object o) {
951 return ConcurrentHashMap.this.remove(o) != null;
952 }
953 public void clear() {
954 ConcurrentHashMap.this.clear();
955 }
956 }
957
958 private class Values extends AbstractCollection<V> {
959 public Iterator<V> iterator() {
960 return new ValueIterator();
961 }
962 public int size() {
963 return ConcurrentHashMap.this.size();
964 }
965 public boolean contains(Object o) {
966 return ConcurrentHashMap.this.containsValue(o);
967 }
968 public void clear() {
969 ConcurrentHashMap.this.clear();
970 }
971 }
972
973 private class EntrySet extends AbstractSet {
974 public Iterator<Map.Entry<K,V>> iterator() {
975 return new EntryIterator();
976 }
977 public boolean contains(Object o) {
978 if (!(o instanceof Map.Entry))
979 return false;
980 Map.Entry<K,V> e = (Map.Entry<K,V>)o;
981 V v = ConcurrentHashMap.this.get(e.getKey());
982 return v != null && v.equals(e.getValue());
983 }
984 public boolean remove(Object o) {
985 if (!(o instanceof Map.Entry))
986 return false;
987 Map.Entry<K,V> e = (Map.Entry<K,V>)o;
988 return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()) != null;
989 }
990 public int size() {
991 return ConcurrentHashMap.this.size();
992 }
993 public void clear() {
994 ConcurrentHashMap.this.clear();
995 }
996 }
997
998 /* ---------------- Serialization Support -------------- */
999
1000 /**
1001 * Save the state of the <tt>ConcurrentHashMap</tt>
1002 * instance to a stream (i.e.,
1003 * serialize it).
1004 * @param s the stream
1005 * @serialData
1006 * the key (Object) and value (Object)
1007 * for each key-value mapping, followed by a null pair.
1008 * The key-value mappings are emitted in no particular order.
1009 */
1010 private void writeObject(java.io.ObjectOutputStream s) throws IOException {
1011 s.defaultWriteObject();
1012
1013 for (int k = 0; k < segments.length; ++k) {
1014 Segment<K,V> seg = segments[k];
1015 seg.lock();
1016 try {
1017 HashEntry<K,V>[] tab = seg.table;
1018 for (int i = 0; i < tab.length; ++i) {
1019 for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
1020 s.writeObject(e.key);
1021 s.writeObject(e.value);
1022 }
1023 }
1024 }
1025 finally {
1026 seg.unlock();
1027 }
1028 }
1029 s.writeObject(null);
1030 s.writeObject(null);
1031 }
1032
1033 /**
1034 * Reconstitute the <tt>ConcurrentHashMap</tt>
1035 * instance from a stream (i.e.,
1036 * deserialize it).
1037 * @param s the stream
1038 */
1039 private void readObject(java.io.ObjectInputStream s)
1040 throws IOException, ClassNotFoundException {
1041 s.defaultReadObject();
1042
1043 // Initialize each segment to be minimally sized, and let grow.
1044 for (int i = 0; i < segments.length; ++i) {
1045 segments[i].setTable(new HashEntry<K,V>[1]);
1046 }
1047
1048 // Read the keys and values, and put the mappings in the table
1049 while (true) {
1050 K key = (K) s.readObject();
1051 V value = (V) s.readObject();
1052 if (key == null)
1053 break;
1054 put(key, value);
1055 }
1056 }
1057 }
1058