ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentReaderHashMap.java
Revision: 1.4
Committed: Fri Jun 6 16:53:04 2003 UTC (21 years ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +0 -0 lines
State: FILE REMOVED
Log Message:
Minor doc updates; FairReentrantLock serialize now

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