ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentReaderHashMap.java
Revision: 1.2
Committed: Thu May 29 13:49:24 2003 UTC (21 years ago) by dl
Branch: MAIN
CVS Tags: JSR166_PRERELEASE_0_1
Changes since 1.1: +1 -1 lines
Log Message:
Please the new generics compiler

File Contents

# User Rev Content
1 dl 1.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     import java.util.*;
9     import java.io.*;
10    
11     /**
12     * A version of Hashtable that supports mostly-concurrent reading, but
13     * exclusive writing. Because reads are not limited to periods
14     * without writes, a concurrent reader policy is weaker than a classic
15     * reader/writer policy, but is generally faster and allows more
16     * concurrency. This class is a good choice especially for tables that
17     * are mainly created by one thread during the start-up phase of a
18     * program, and from then on, are mainly read (with perhaps occasional
19     * additions or removals) in many threads. If you also need concurrency
20     * among writes, consider instead using ConcurrentHashMap.
21     * <p>
22     *
23     * Successful retrievals using get(key) and containsKey(key) usually
24     * run without locking. Unsuccessful ones (i.e., when the key is not
25     * present) do involve brief synchronization (locking). Also, the
26     * size and isEmpty methods are always synchronized.
27     *
28     * <p> Because retrieval operations can ordinarily overlap with
29     * writing operations (i.e., put, remove, and their derivatives),
30     * retrievals can only be guaranteed to return the results of the most
31     * recently <em>completed</em> operations holding upon their
32     * onset. Retrieval operations may or may not return results
33     * reflecting in-progress writing operations. However, the retrieval
34     * operations do always return consistent results -- either those
35     * holding before any single modification or after it, but never a
36     * nonsense result. For aggregate operations such as putAll and
37     * clear, concurrent reads may reflect insertion or removal of only
38     * some entries. In those rare contexts in which you use a hash table
39     * to synchronize operations across threads (for example, to prevent
40     * reads until after clears), you should either encase operations
41     * in synchronized blocks, or instead use java.util.Hashtable.
42     *
43     */
44    
45     public class ConcurrentReaderHashMap<K,V> extends Dictionary<K,V>
46     implements ConcurrentMap<K,V>, Cloneable, Serializable {
47    
48     /*
49     * This implementation is thread-safe, but not heavily
50     * synchronized. The basic strategy is to ensure that the hash
51     * table and its lists are ALWAYS kept in a consistent state, so
52     * can be read without locking. Next fields of nodes are
53     * immutable (final). All list additions are performed at the
54     * front of each bin. This makes it easy to check changes, and
55     * also fast to traverse. When nodes would otherwise be changed,
56     * new nodes are created to replace them. This works well for hash
57     * tables since the bin lists tend to be short. (The average
58     * length is less than two for the default load factor threshold.)
59     *
60     * Read operations can thus proceed without locking, but rely on a
61     * memory barrier to ensure that COMPLETED write operations
62     * performed by other threads are noticed. Conveniently, the
63     * "count" field, tracking the number of elements, can also serve
64     * as the volatile variable providing proper read/write
65     * barriers. This is convenient because this field needs to be
66     * read in many read operations anyway. The use of volatiles for
67     * this purpose is only guaranteed to work in accord with normal
68     * expectations in multithreaded environments when run on JVMs
69     * conforming to the clarified JSR133 memory model specification.
70     * This true for hotspot as of release 1.4.
71     *
72     * Implementors note. The basic rules for all this are:
73     * - All unsynchronized read operations must first read
74     * the "count" field, and generally, should not look at table if 0.
75     *
76     * - All synchronized write operations should write to
77     * the "count" field after updating. The operations may not
78     * take any action that could even momentarily cause
79     * a concurrent read operation to see inconsistent
80     * data. This is made easier by the nature of the read
81     * operations in ConcurrentReaderHashMap. For example, no operation
82     * can reveal that the table has grown but the threshold
83     * has not yet been updated, so there are no atomicity
84     * requirements for this with respect to reads.
85     *
86     * As a guide, all critical volatile reads and writes are marked
87     * in the code as comments.
88     */
89    
90     /** use serialVersionUID from JDK 1.0.2 for interoperability */
91     private static final long serialVersionUID = 1421746759512286392L;
92    
93     /**
94     * The default initial number of table slots for this table (32).
95     * Used when not otherwise specified in constructor.
96     */
97     static int DEFAULT_INITIAL_CAPACITY = 16;
98    
99     /**
100     * The maximum capacity, used if a higher value is implicitly
101     * specified by either of the constructors with arguments. MUST
102     * be a power of two <= 1<<30.
103     */
104     static final int MAXIMUM_CAPACITY = 1 << 30;
105    
106     /**
107     * The default load factor for this table. Used when not
108     * otherwise specified in constructor.
109     */
110    
111     static final float DEFAULT_LOAD_FACTOR = 0.75f;
112    
113     /**
114     * The total number of mappings in the hash table.
115     * Also serves as the read-barrier variable.
116     */
117     private transient volatile int count;
118    
119     /**
120     * The hash table data.
121     */
122     private transient HashEntry<K,V>[] table;
123    
124     /**
125     * The load factor for the hash table. This is also used as a
126     * recursion flag in method hashCode. (Sorry for the sleaze but
127     * this maintains 1.1 compatibility.)
128     *
129     * @serial
130     */
131     private float loadFactor;
132    
133     /**
134     * The table is rehashed when its size exceeds this threshold.
135     * (The value of this field is always (int)(capacity *
136     * loadFactor).)
137     *
138     * @serial
139     */
140     private int threshold;
141    
142     /**
143     * The number of times this map has been structurally modified
144     * Structural modifications are those that change the number of
145     * mappings in the map or otherwise modify its internal structure
146     * (e.g., rehash). This field is used to make iterators on
147     * Collection-views of the map fail-fast. (See
148     * ConcurrentModificationException).
149     */
150     private transient int modCount;
151    
152     // internal utilities
153    
154     /**
155     * Return a hash code for non-null Object x.
156     */
157     private static int hash(Object x) {
158     int h = x.hashCode();
159     h += ~(h << 9);
160     h ^= (h >>> 14);
161     h += (h << 4);
162     h ^= (h >>> 10);
163     return h;
164     }
165    
166     /**
167     * Check for equality of non-null references x and y.
168     **/
169     private static boolean eq(Object x, Object y) {
170     return x == y || x.equals(y);
171     }
172    
173     /**
174     * Return index for hash code h.
175     */
176     private static int indexFor(int h, int length) {
177     return h & (length-1);
178     }
179    
180     /**
181     * Set table to new HashEntry array.
182     * Call only while holding lock or in constructor.
183     **/
184     private void setTable(HashEntry<K,V>[] newTable) {
185     table = newTable;
186     threshold = (int)(newTable.length * loadFactor);
187     count = count; // write-volatile
188     }
189    
190     /**
191     * Constructs a new, empty map with a default initial capacity
192     * and load factor.
193     */
194     public ConcurrentReaderHashMap() {
195     loadFactor = DEFAULT_LOAD_FACTOR;
196     setTable(new HashEntry[DEFAULT_INITIAL_CAPACITY]);
197     }
198    
199     /**
200     * Constructs a new, empty map with the specified initial
201     * capacity and the specified load factor.
202     *
203     * @param initialCapacity the initial capacity
204     * The actual initial capacity is rounded to the nearest power of two.
205     * @param loadFactor the load factor of the ConcurrentReaderHashMap
206     * @throws IllegalArgumentException if the initial capacity is less
207     * than zero, or if the load factor is nonpositive.
208     */
209     public ConcurrentReaderHashMap(int initialCapacity, float loadFactor) {
210     if (initialCapacity < 0)
211     throw new IllegalArgumentException("Illegal initial capacity: " +
212     initialCapacity);
213     if (loadFactor <= 0 || Float.isNaN(loadFactor))
214     throw new IllegalArgumentException("Illegal Load factor: "+
215     loadFactor);
216     this.loadFactor = loadFactor;
217    
218     int capacity;
219     if (initialCapacity > MAXIMUM_CAPACITY)
220     capacity = MAXIMUM_CAPACITY;
221     else {
222     capacity = 1;
223     while (capacity < initialCapacity)
224     capacity <<= 1;
225     }
226    
227     setTable(new HashEntry[capacity]);
228     }
229    
230     /**
231     * Constructs a new, empty map with the specified initial
232     * capacity and default load factor.
233     *
234     * @param initialCapacity the initial capacity of the
235     * ConcurrentReaderHashMap.
236     * The actual initial capacity is rounded to the nearest power of two.
237     * @throws IllegalArgumentException if the initial maximum number
238     * of elements is less
239     * than zero.
240     */
241    
242     public ConcurrentReaderHashMap(int initialCapacity) {
243     this(initialCapacity, DEFAULT_LOAD_FACTOR);
244     }
245    
246     /**
247     * Constructs a new map with the same mappings as the given map. The
248     * map is created with a default load factor.
249     */
250    
251     public ConcurrentReaderHashMap(Map<K,V> t) {
252     this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, 16),
253     DEFAULT_LOAD_FACTOR);
254     putAll(t);
255     }
256    
257    
258     /**
259     * Returns the number of key-value mappings in this map.
260     *
261     * @return the number of key-value mappings in this map.
262     */
263     public int size() {
264     return count; // read-volatile
265     }
266    
267     /**
268     * Returns <tt>true</tt> if this map contains no key-value mappings.
269     *
270     * @return <tt>true</tt> if this map contains no key-value mappings.
271     */
272     public boolean isEmpty() {
273     return count == 0; // read-volatile
274     }
275    
276     /**
277     * Returns the value to which the specified key is mapped in this table.
278     *
279     * @param key a key in the table.
280     * @return the value to which the key is mapped in this table;
281     * <code>null</code> if the key is not mapped to any value in
282     * this table.
283     * @exception NullPointerException if the key is
284     * <code>null</code>.
285     * @see #put(Object, Object)
286     */
287 dl 1.2 public V get(K key) {
288 dl 1.1 int hash = hash(key); // throws NullPointerException if key null
289    
290     if (count != 0) { // read-volatile
291     HashEntry<K,V>[] tab = table;
292     int index = indexFor(hash, tab.length);
293     HashEntry<K,V> e = tab[index];
294     while (e != null) {
295     if (e.hash == hash && eq(key, e.key))
296     return e.value;
297     e = e.next;
298     }
299     }
300     return null;
301     }
302    
303     /**
304     * Tests if the specified object is a key in this table.
305     *
306     * @param key possible key.
307     * @return <code>true</code> if and only if the specified object
308     * is a key in this table, as determined by the
309     * <tt>equals</tt> method; <code>false</code> otherwise.
310     * @exception NullPointerException if the key is
311     * <code>null</code>.
312     * @see #contains(Object)
313     */
314     public boolean containsKey(Object key) {
315     int hash = hash(key); // throws NullPointerException if key null
316    
317     if (count != 0) { // read-volatile
318     HashEntry<K,V>[] tab = table;
319     int index = indexFor(hash, tab.length);
320     HashEntry<K,V> e = tab[index];
321     while (e != null) {
322     if (e.hash == hash && eq(key, e.key))
323     return true;
324     e = e.next;
325     }
326     }
327     return false;
328     }
329    
330     /**
331     * Returns <tt>true</tt> if this map maps one or more keys to the
332     * specified value. Note: This method requires a full internal
333     * traversal of the hash table, and so is much slower than
334     * method <tt>containsKey</tt>.
335     *
336     * @param value value whose presence in this map is to be tested.
337     * @return <tt>true</tt> if this map maps one or more keys to the
338     * specified value.
339     * @exception NullPointerException if the value is <code>null</code>.
340     */
341     public boolean containsValue(Object value) {
342     if (value == null)
343     throw new NullPointerException();
344    
345     if (count != 0) {
346     HashEntry tab[] = table;
347     int len = tab.length;
348     for (int i = 0 ; i < len; i++)
349     for (HashEntry e = tab[i] ; e != null ; e = e.next)
350     if (value.equals(e.value))
351     return true;
352     }
353     return false;
354     }
355    
356    
357     /**
358     * Tests if some key maps into the specified value in this table.
359     * This operation is more expensive than the <code>containsKey</code>
360     * method.<p>
361     *
362     * Note that this method is identical in functionality to containsValue,
363     * (which is part of the Map interface in the collections framework).
364     *
365     * @param value a value to search for.
366     * @return <code>true</code> if and only if some key maps to the
367     * <code>value</code> argument in this table as
368     * determined by the <tt>equals</tt> method;
369     * <code>false</code> otherwise.
370     * @exception NullPointerException if the value is <code>null</code>.
371     * @see #containsKey(Object)
372     * @see #containsValue(Object)
373     * @see Map
374     */
375     public boolean contains(Object value) {
376     return containsValue(value);
377     }
378    
379     /**
380     * Maps the specified <code>key</code> to the specified
381     * <code>value</code> in this table. Neither the key nor the
382     * value can be <code>null</code>. <p>
383     *
384     * The value can be retrieved by calling the <code>get</code> method
385     * with a key that is equal to the original key.
386     *
387     * @param key the table key.
388     * @param value the value.
389     * @return the previous value of the specified key in this table,
390     * or <code>null</code> if it did not have one.
391     * @exception NullPointerException if the key or value is
392     * <code>null</code>.
393     * @see Object#equals(Object)
394     * @see #get(Object)
395     */
396     public synchronized V put(K key, V value) {
397     if (value == null)
398     throw new NullPointerException();
399     int hash = hash(key);
400     HashEntry<K,V>[] tab = table;
401     int index = indexFor(hash, tab.length);
402     HashEntry<K,V> first = tab[index];
403    
404     for (HashEntry<K,V> e = first; e != null; e = e.next) {
405     if (e.hash == hash && eq(key, e.key)) {
406     V oldValue = e.value;
407     e.value = value;
408     count = count; // write-volatile
409     return oldValue;
410     }
411     }
412    
413     tab[index] = new HashEntry(hash, key, value, first);
414     modCount++;
415     if (++count > threshold) // write-volatile
416     rehash();
417     return null;
418     }
419    
420     public synchronized V putIfAbsent(K key, V value) {
421     if (value == null)
422     throw new NullPointerException();
423     int hash = hash(key);
424     HashEntry<K,V>[] tab = table;
425     int index = indexFor(hash, tab.length);
426     HashEntry<K,V> first = tab[index];
427    
428     for (HashEntry<K,V> e = first; e != null; e = e.next) {
429     if (e.hash == hash && eq(key, e.key)) {
430     V oldValue = e.value;
431     count = count; // write-volatile
432     return oldValue;
433     }
434     }
435    
436     tab[index] = new HashEntry(hash, key, value, first);
437     modCount++;
438     if (++count > threshold) // write-volatile
439     rehash();
440     return value;
441     }
442    
443     /**
444     * Rehashes the contents of this map into a new table
445     * with a larger capacity. This method is called automatically when the
446     * number of keys in this map exceeds the load factor threshold.
447     */
448     private void rehash() {
449     HashEntry<K,V>[] oldTable = table;
450     int oldCapacity = oldTable.length;
451     if (oldCapacity < MAXIMUM_CAPACITY) {
452     HashEntry<K,V>[] newTable = new HashEntry<K,V>[oldCapacity << 1];
453     transfer(oldTable, newTable);
454     setTable(newTable);
455     }
456     }
457    
458     /**
459     * Transfer nodes from old table to new table.
460     */
461     private void transfer(HashEntry<K,V>[] oldTable, HashEntry<K,V>[] newTable) {
462     /*
463     * Reclassify nodes in each list to new Map. Because we are
464     * using power-of-two expansion, the elements from each bin
465     * must either stay at same index, or move with a power of two
466     * offset. We eliminate unnecessary node creation by catching
467     * cases where old nodes can be reused because their next
468     * fields won't change. Statistically, at the default
469     * threshhold, only about one-sixth of them need cloning when
470     * a table doubles. The nodes they replace will be garbage
471     * collectable as soon as they are no longer referenced by any
472     * reader thread that may be in the midst of traversing table
473     * right now.
474     */
475    
476     int oldCapacity = oldTable.length;
477     int mask = newTable.length - 1;
478     for (int i = 0; i < oldCapacity ; i++) {
479     // We need to guarantee that any existing reads of old Map can
480     // proceed. So we cannot yet null out each bin.
481     HashEntry<K,V> e = oldTable[i];
482    
483     if (e != null) {
484     HashEntry<K,V> next = e.next;
485     int idx = e.hash & mask;
486    
487     // Single node on list
488     if (next == null)
489     newTable[idx] = e;
490    
491     else {
492     // Reuse trailing consecutive sequence at same slot
493     HashEntry<K,V> lastRun = e;
494     int lastIdx = idx;
495     for (HashEntry<K,V> last = next; last != null; last = last.next) {
496     int k = last.hash & mask;
497     if (k != lastIdx) {
498     lastIdx = k;
499     lastRun = last;
500     }
501     }
502     newTable[lastIdx] = lastRun;
503    
504     // Clone all remaining nodes
505     for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
506     int k = p.hash & mask;
507     newTable[k] = new HashEntry(p.hash, p.key,
508     p.value, newTable[k]);
509     }
510     }
511     }
512     }
513     }
514    
515    
516     /**
517     * Copies all of the mappings from the specified map to this one.
518     *
519     * These mappings replace any mappings that this map had for any of the
520     * keys currently in the specified Map.
521     *
522     * @param t Mappings to be stored in this map.
523     */
524    
525     public <K1 extends K, V1 extends V> void putAll(Map<K1,V1> t) {
526     int n = t.size();
527     // Expand enough to hold at least n elements without resizing.
528     if (n >= threshold)
529     resizeToFit(n);
530     Iterator<Map.Entry<K1,V1>> it = t.entrySet().iterator();
531     while (it.hasNext()) {
532     Entry<K,V> e = (Entry) it.next();
533     put(e.getKey(), e.getValue());
534     }
535     }
536    
537     /**
538     * Resize by enough to fit n elements.
539     */
540     private synchronized void resizeToFit(int n) {
541     int newSize = (int)(n / loadFactor + 1);
542     if (newSize > MAXIMUM_CAPACITY)
543     newSize = MAXIMUM_CAPACITY;
544    
545     HashEntry[] oldTable = table;
546     int oldCapacity = oldTable.length;
547     int newCapacity = oldCapacity;
548     while (newCapacity < newSize)
549     newCapacity <<= 1;
550    
551     if (newCapacity > oldCapacity) {
552     HashEntry[] newTable = new HashEntry[newCapacity];
553     if (count != 0)
554     transfer(oldTable, newTable);
555     setTable(newTable);
556     }
557     }
558    
559    
560     /**
561     * Removes the key (and its corresponding value) from this
562     * table. This method does nothing if the key is not in the table.
563     *
564     * @param key the key that needs to be removed.
565     * @return the value to which the key had been mapped in this table,
566     * or <code>null</code> if the key did not have a mapping.
567     * @exception NullPointerException if the key is
568     * <code>null</code>.
569     */
570     public synchronized V remove(Object key) {
571     int hash = hash(key);
572     HashEntry[] tab = table;
573     int index = indexFor(hash, tab.length);
574     HashEntry<K,V> first = tab[index];
575    
576     HashEntry<K,V> e = first;
577     while (true) {
578     if (e == null)
579     return null;
580     if (e.hash == hash && eq(key, e.key))
581     break;
582     e = e.next;
583     }
584    
585     // All entries following removed node can stay in list, but
586     // all preceeding ones need to be cloned.
587     HashEntry<K,V> newFirst = e.next;
588     for (HashEntry<K,V> p = first; p != e; p = p.next)
589     newFirst = new HashEntry(p.hash, p.key, p.value, newFirst);
590     tab[index] = newFirst;
591    
592     modCount++;
593     count--; // write-volatile
594     return e.value;
595     }
596    
597    
598     /**
599     * Helper method for entrySet.remove
600     */
601     private synchronized boolean findAndRemoveHashEntry(K key,
602     V value) {
603     return key != null && value != null &&
604     value.equals(get(key)) && (remove(key) != null);
605     }
606    
607     /**
608     * Removes all mappings from this map.
609     */
610     public synchronized void clear() {
611     modCount++;
612     HashEntry<K,V> tab[] = table;
613     int len = tab.length;
614     for (int i = 0; i < len ; i++)
615     tab[i] = null;
616     count = 0; // write-volatile
617     }
618    
619    
620     /**
621     * Returns a string representation of this <tt>ConcurrentReaderHashMap</tt> object
622     * in the form of a set of entries, enclosed in braces and separated
623     * by the ASCII characters "<tt>,&nbsp;</tt>" (comma and space). Each
624     * entry is rendered as the key, an equals sign <tt>=</tt>, and the
625     * associated element, where the <tt>toString</tt> method is used to
626     * convert the key and element to strings. <p>Overrides to
627     * <tt>toString</tt> method of <tt>Object</tt>.
628     *
629     * @return a string representation of this hashtable.
630     */
631     public String toString() {
632     if (count == 0) // read-volatile
633     return "{}";
634    
635     StringBuffer buf = new StringBuffer();
636     buf.append("{");
637    
638     HashEntry<K,V> tab[] = table;
639     int len = tab.length;
640     int k = 0;
641     for (int i = 0 ; i < len; i++) {
642     for (HashEntry<K,V> e = tab[i] ; e != null ; e = e.next) {
643     if (k++ != 0)
644     buf.append(", ");
645     Object key = e.getKey();
646     Object value = e.getValue();
647    
648     buf.append((key == this ? "(this Map)" : key) + "=" +
649     (value == this ? "(this Map)": value));
650     }
651     }
652     buf.append("}");
653     return buf.toString();
654     }
655    
656     /**
657     * Compares the specified Object with this Map for equality,
658     * as per the definition in the Map interface.
659     *
660     * @return true if the specified Object is equal to this Map.
661     * @see Map#equals(Object)
662     * @since 1.2
663     */
664     public boolean equals(Object o) {
665     if (o == this)
666     return true;
667     if (!(o instanceof Map))
668     return false;
669    
670     Map t = (Map) o;
671     if (t.size() != count) // read-volatile
672     return false;
673    
674     HashEntry<K,V> tab[] = table;
675     int len = tab.length;
676     for (int i = 0 ; i < len; i++) {
677     for (HashEntry<K,V> e = tab[i] ; e != null ; e = e.next) {
678     Object v = t.get(e.key);
679     if (v == null || !v.equals(e.value))
680     return false;
681     }
682     }
683     return true;
684     }
685    
686     /**
687     * Returns the hash code value for this Map as per the definition in the
688     * Map interface.
689     *
690     * @see Map#hashCode()
691     * @since 1.2
692     */
693     public synchronized int hashCode() {
694     /*
695     This implementation maintains compatibility with
696     JDK1.1 to allow computing hashCodes for ConcurrentReaderHashMaps
697     with reference cycles. This requires both synchronization
698     and temporary abuse of the "loadFactor" field to signify
699     that a hashCode is in the midst of being computed so
700     to ignore recursive calls. It is embarassing
701     to use loadFactor in this way, but this tactic permits
702     handling the case without any other field changes.
703    
704     Even though hashCodes of cyclic structures can be computed,
705     programs should NOT insert a ConcurrentReaderHashMap into itself. Because
706     its hashCode changes as a result of entering itself, it is
707     normally impossible to retrieve the embedded ConcurrentReaderHashMap using
708     get().
709     */
710     int h = 0;
711     float lf = loadFactor;
712     if (count != 0 && lf > 0) {
713     loadFactor = 0; // zero as recursion flag
714     HashEntry<K,V> tab[] = table;
715     int len = tab.length;
716     for (int i = 0 ; i < len; i++)
717     for (HashEntry<K,V> e = tab[i] ; e != null ; e = e.next)
718     h += e.key.hashCode() ^ e.value.hashCode();
719     loadFactor = lf;
720     }
721     return h;
722     }
723    
724    
725     /**
726     * Returns a shallow copy of this
727     * <tt>ConcurrentReaderHashMap</tt> instance: the keys and
728     * values themselves are not cloned.
729     *
730     * @return a shallow copy of this map.
731     */
732     public synchronized Object clone() {
733     ConcurrentReaderHashMap result = null;
734     try {
735     result = (ConcurrentReaderHashMap)super.clone();
736     }
737     catch (CloneNotSupportedException e) {
738     // assert false;
739     }
740     result.count = 0;
741     result.keySet = null;
742     result.entrySet = null;
743     result.values = null;
744     result.modCount = 0;
745     result.table = new HashEntry[table.length];
746     result.putAll(this);
747     return result;
748     }
749    
750     /**
751     * ConcurrentReaderHashMap collision list entry.
752     */
753     private static class HashEntry<K,V> implements Entry<K,V> {
754     private final K key;
755     private V value;
756     private final int hash;
757     private final HashEntry<K,V> next;
758    
759     HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
760     this.value = value;
761     this.hash = hash;
762     this.key = key;
763     this.next = next;
764     }
765    
766     public K getKey() {
767     return key;
768     }
769    
770     public V getValue() {
771     return value;
772     }
773    
774     public V setValue(V newValue) {
775     // We aren't required to, and don't provide any
776     // visibility barriers for setting value.
777     if (newValue == null)
778     throw new NullPointerException();
779     V oldValue = this.value;
780     this.value = newValue;
781     return oldValue;
782     }
783    
784     public boolean equals(Object o) {
785     if (!(o instanceof Entry))
786     return false;
787     Entry<K,V> e = (Entry)o;
788     return (key.equals(e.getKey()) && value.equals(e.getValue()));
789     }
790    
791     public int hashCode() {
792     return key.hashCode() ^ value.hashCode();
793     }
794    
795     public String toString() {
796     return key + "=" + value;
797     }
798     }
799    
800     /**
801     * Support for Enumeration interface. These Enumerations take a
802     * snapshot of table, so can never encounter corrupted
803     * representations in multithreaded programs. At worst, they will
804     * report the presence of entries deleted since the enumeration
805     * was constructed, or absence of those inserted.
806     */
807    
808     private abstract class HashEnumerator {
809    
810    
811     HashEntry<K,V> next; // next entry to return
812     final HashEntry[] tab; // snapshot of table
813     int index; // current slot
814    
815     HashEnumerator(int size, HashEntry<K,V>[] t) {
816     tab = t;
817     int i = t.length;
818     HashEntry<K,V> n = null;
819     if (size != 0) { // advance to first entry
820     while (i > 0 && (n = tab[--i]) == null)
821     ;
822     }
823     next = n;
824     index = i;
825     }
826    
827     public boolean hasMoreElements() {
828     return next != null;
829     }
830    
831     HashEntry<K,V> nextHashEntry() {
832     HashEntry<K,V> e = next;
833     if (e == null)
834     throw new NoSuchElementException("ConcurrentReaderHashMap Enumerator");
835    
836     HashEntry<K,V> n = e.next;
837     int i = index;
838     while (n == null && i > 0)
839     n = tab[--i];
840     index = i;
841     next = n;
842     return e;
843     }
844     }
845    
846     private class KeyEnumerator extends HashEnumerator implements Enumeration<K> {
847     KeyEnumerator(int size, HashEntry<K,V>[] t) { super(size, t); }
848     public K nextElement() {
849     return nextHashEntry().key;
850     }
851     }
852    
853     private class ValueEnumerator extends HashEnumerator implements Enumeration<V> {
854     ValueEnumerator(int size, HashEntry<K,V>[] t) { super(size, t); }
855     public V nextElement() {
856     return nextHashEntry().value;
857     }
858     }
859    
860     /**
861     * Support for Iterator interface.
862     */
863     private abstract class HashIterator {
864     HashEntry<K,V> next; // next entry to return
865     int expectedModCount; // For fast-fail
866     int index; // current slot
867     HashEntry<K,V> current; // current entry
868    
869     HashIterator() {
870     int size = count; // read-volatile
871     HashEntry[] t = table;
872     expectedModCount = modCount;
873     int i = t.length;
874     HashEntry<K,V> n = null;
875     if (size != 0) { // advance to first entry
876     while (i > 0 && (n = t[--i]) == null)
877     ;
878     }
879     next = n;
880     index = i;
881     }
882    
883     public boolean hasNext() {
884     return next != null;
885     }
886    
887     HashEntry<K,V> nextHashEntry() {
888     int ignore = count; // read-volatile
889     if (modCount != expectedModCount)
890     throw new ConcurrentModificationException();
891     HashEntry<K,V> e = next;
892     if (e == null)
893     throw new NoSuchElementException("ConcurrentReaderHashMap Enumerator");
894    
895     HashEntry<K,V> n = e.next;
896     HashEntry[] t = table;
897     int i = index;
898     while (n == null && i > 0)
899     n = t[--i];
900     index = i;
901     next = n;
902     current = e;
903     return e;
904     }
905    
906     public void remove() {
907     if (current == null)
908     throw new IllegalStateException("ConcurrentReaderHashMap Enumerator");
909     K k = current.key;
910     current = null;
911     if (ConcurrentReaderHashMap.this.remove(k) == null)
912     throw new ConcurrentModificationException();
913     expectedModCount = modCount;
914     }
915     }
916    
917     private class KeyIterator extends HashIterator implements Iterator<K> {
918     KeyIterator() {}
919     public K next() {
920     return nextHashEntry().key;
921     }
922     }
923    
924     private class ValueIterator extends HashIterator implements Iterator<V> {
925     ValueIterator() {}
926     public V next() {
927     return nextHashEntry().value;
928     }
929     }
930    
931     private class HashEntryIterator extends HashIterator implements Iterator<Entry<K,V>> {
932     HashEntryIterator() {}
933     public Entry<K,V> next() {
934     return nextHashEntry();
935     }
936     }
937    
938    
939     // Views
940    
941     private transient Set<K> keySet = null;
942     private transient Set/*<Entry<K,V>>*/ entrySet = null;
943     private transient Collection<V> values = null;
944    
945     /**
946     * Returns a set view of the keys contained in this map. The set is
947     * backed by the map, so changes to the map are reflected in the set, and
948     * vice-versa. The set supports element removal, which removes the
949     * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
950     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
951     * <tt>clear</tt> operations. It does not support the <tt>add</tt> or
952     * <tt>addAll</tt> operations.
953     *
954     * @return a set view of the keys contained in this map.
955     */
956    
957     public Set<K> keySet() {
958     Set<K> ks = keySet;
959     return (ks != null)? ks : (keySet = new KeySet());
960     }
961    
962     private class KeySet extends AbstractSet<K> {
963     public Iterator<K> iterator() {
964     return new KeyIterator();
965     }
966     public int size() {
967     return ConcurrentReaderHashMap.this.size();
968     }
969     public boolean contains(Object o) {
970     return ConcurrentReaderHashMap.this.containsKey(o);
971     }
972     public boolean remove(Object o) {
973     return ConcurrentReaderHashMap.this.remove(o) != null;
974     }
975     public void clear() {
976     ConcurrentReaderHashMap.this.clear();
977     }
978     }
979    
980     /**
981     * Returns a collection view of the values contained in this map. The
982     * collection is backed by the map, so changes to the map are reflected in
983     * the collection, and vice-versa. The collection supports element
984     * removal, which removes the corresponding mapping from this map, via the
985     * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
986     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
987     * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
988     *
989     * @return a collection view of the values contained in this map.
990     */
991    
992     public Collection<V> values() {
993     Collection<V> vs = values;
994     return (vs != null)? vs : (values = new Values());
995     }
996    
997     private class Values extends AbstractCollection<V> {
998     public Iterator<V> iterator() {
999     return new ValueIterator();
1000     }
1001     public int size() {
1002     return ConcurrentReaderHashMap.this.size();
1003     }
1004     public boolean contains(Object o) {
1005     return ConcurrentReaderHashMap.this.containsValue(o);
1006     }
1007     public void clear() {
1008     ConcurrentReaderHashMap.this.clear();
1009     }
1010     }
1011    
1012     /**
1013     * Returns a collection view of the mappings contained in this map. Each
1014     * element in the returned collection is a <tt>Entry</tt>. The
1015     * collection is backed by the map, so changes to the map are reflected in
1016     * the collection, and vice-versa. The collection supports element
1017     * removal, which removes the corresponding mapping from the map, via the
1018     * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
1019     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
1020     * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
1021     *
1022     * @return a collection view of the mappings contained in this map.
1023     * @see Entry
1024     */
1025    
1026     public Set<Entry<K,V>> entrySet() {
1027     Set<Entry<K,V>> es = entrySet;
1028     return (es != null) ? es : (entrySet = new EntrySet());
1029     }
1030    
1031     private class EntrySet extends AbstractSet {
1032     public Iterator<Entry<K,V>> iterator() {
1033     return new HashEntryIterator();
1034     }
1035     public boolean contains(Object o) {
1036     if (!(o instanceof Entry))
1037     return false;
1038     Entry<K,V> entry = (Entry)o;
1039     Object v = ConcurrentReaderHashMap.this.get(entry.getKey());
1040     return v != null && v.equals(entry.getValue());
1041     }
1042     public boolean remove(Object o) {
1043     if (!(o instanceof Entry))
1044     return false;
1045     Entry<K,V> entry = (Entry)o;
1046     return ConcurrentReaderHashMap.this.findAndRemoveHashEntry(entry.getKey(),
1047     entry.getValue());
1048     }
1049     public int size() {
1050     return ConcurrentReaderHashMap.this.size();
1051     }
1052     public void clear() {
1053     ConcurrentReaderHashMap.this.clear();
1054     }
1055     }
1056    
1057     /**
1058     * Returns an enumeration of the keys in this table.
1059     *
1060     * @return an enumeration of the keys in this table.
1061     * @see Enumeration
1062     * @see #elements()
1063     * @see #keySet()
1064     * @see Map
1065     */
1066     public Enumeration<K> keys() {
1067     int n = count; // read-volatile
1068     return new KeyEnumerator(n, table);
1069     }
1070    
1071     /**
1072     * Returns an enumeration of the values in this table.
1073     * Use the Enumeration methods on the returned object to fetch the elements
1074     * sequentially.
1075     *
1076     * @return an enumeration of the values in this table.
1077     * @see java.util.Enumeration
1078     * @see #keys()
1079     * @see #values()
1080     * @see Map
1081     */
1082    
1083     public Enumeration<V> elements() {
1084     int n = count; // read-volatile
1085     return new ValueEnumerator(n, table);
1086     }
1087    
1088     /**
1089     * Save the state of the <tt>ConcurrentReaderHashMap</tt>
1090     * instance to a stream (i.e.,
1091     * serialize it).
1092     *
1093     * @serialData The <i>capacity</i> of the
1094     * ConcurrentReaderHashMap (the length of the
1095     * bucket array) is emitted (int), followed by the
1096     * <i>size</i> of the ConcurrentReaderHashMap (the number of key-value
1097     * mappings), followed by the key (Object) and value (Object)
1098     * for each key-value mapping represented by the ConcurrentReaderHashMap
1099     * The key-value mappings are emitted in no particular order.
1100     */
1101    
1102     private synchronized void writeObject(java.io.ObjectOutputStream s)
1103     throws IOException {
1104     // Write out the threshold, loadfactor, and any hidden stuff
1105     s.defaultWriteObject();
1106    
1107     // Write out number of buckets
1108     s.writeInt(table.length);
1109    
1110     // Write out size (number of Mappings)
1111     s.writeInt(count);
1112    
1113     // Write out keys and values (alternating)
1114     for (int index = table.length-1; index >= 0; index--) {
1115     HashEntry<K,V> entry = table[index];
1116    
1117     while (entry != null) {
1118     s.writeObject(entry.key);
1119     s.writeObject(entry.value);
1120     entry = entry.next;
1121     }
1122     }
1123     }
1124    
1125     /**
1126     * Reconstitute the <tt>ConcurrentReaderHashMap</tt>
1127     * instance from a stream (i.e.,
1128     * deserialize it).
1129     */
1130     private synchronized void readObject(java.io.ObjectInputStream s)
1131     throws IOException, ClassNotFoundException {
1132     // Read in the threshold, loadfactor, and any hidden stuff
1133     s.defaultReadObject();
1134    
1135     // Read in number of buckets and allocate the bucket array;
1136     int numBuckets = s.readInt();
1137     table = new HashEntry[numBuckets];
1138    
1139     // Read in size (number of Mappings)
1140     int size = s.readInt();
1141    
1142     // Read the keys and values, and put the mappings in the table
1143     for (int i=0; i<size; i++) {
1144     K key = (K)(s.readObject());
1145     V value = (V)(s.readObject());
1146     put(key, value);
1147     }
1148     }
1149    
1150     }