ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentHashMap.java
(Generate patch)

Comparing jsr166/src/main/java/util/concurrent/ConcurrentHashMap.java (file contents):
Revision 1.52 by dl, Mon Jul 12 11:01:14 2004 UTC vs.
Revision 1.94 by jsr166, Mon Dec 4 02:20:06 2006 UTC

# Line 33 | Line 33 | import java.io.ObjectOutputStream;
33   * removal of only some entries.  Similarly, Iterators and
34   * Enumerations return elements reflecting the state of the hash table
35   * at some point at or since the creation of the iterator/enumeration.
36 < * They do <em>not</em> throw
37 < * {@link ConcurrentModificationException}.  However, iterators are
38 < * designed to be used by only one thread at a time.
36 > * They do <em>not</em> throw {@link ConcurrentModificationException}.
37 > * However, iterators are designed to be used by only one thread at a time.
38   *
39   * <p> The allowed concurrency among update operations is guided by
40   * the optional <tt>concurrencyLevel</tt> constructor argument
41 < * (default 16), which is used as a hint for internal sizing.  The
41 > * (default <tt>16</tt>), which is used as a hint for internal sizing.  The
42   * table is internally partitioned to try to permit the indicated
43   * number of concurrent updates without contention. Because placement
44   * in hash tables is essentially random, the actual concurrency will
# Line 59 | Line 58 | import java.io.ObjectOutputStream;
58   * <em>optional</em> methods of the {@link Map} and {@link Iterator}
59   * interfaces.
60   *
61 < * <p> Like {@link java.util.Hashtable} but unlike {@link
62 < * java.util.HashMap}, this class does NOT allow <tt>null</tt> to be
64 < * used as a key or value.
61 > * <p> Like {@link Hashtable} but unlike {@link HashMap}, this class
62 > * does <em>not</em> allow <tt>null</tt> to be used as a key or value.
63   *
64   * <p>This class is a member of the
65 < * <a href="{@docRoot}/../guide/collections/index.html">
65 > * <a href="{@docRoot}/../technotes/guides/collections/index.html">
66   * Java Collections Framework</a>.
67   *
68   * @since 1.5
69   * @author Doug Lea
70   * @param <K> the type of keys maintained by this map
71 < * @param <V> the type of mapped values
71 > * @param <V> the type of mapped values
72   */
73   public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
74          implements ConcurrentMap<K, V>, Serializable {
# Line 84 | Line 82 | public class ConcurrentHashMap<K, V> ext
82      /* ---------------- Constants -------------- */
83  
84      /**
85 <     * The default initial number of table slots for this table.
86 <     * Used when not otherwise specified in constructor.
85 >     * The default initial capacity for this table,
86 >     * used when not otherwise specified in a constructor.
87       */
88 <    static int DEFAULT_INITIAL_CAPACITY = 16;
88 >    static final int DEFAULT_INITIAL_CAPACITY = 16;
89  
90      /**
91 <     * The maximum capacity, used if a higher value is implicitly
92 <     * specified by either of the constructors with arguments.  MUST
95 <     * be a power of two <= 1<<30 to ensure that entries are indexible
96 <     * using ints.
91 >     * The default load factor for this table, used when not
92 >     * otherwise specified in a constructor.
93       */
94 <    static final int MAXIMUM_CAPACITY = 1 << 30;
94 >    static final float DEFAULT_LOAD_FACTOR = 0.75f;
95  
96      /**
97 <     * The default load factor for this table.  Used when not
98 <     * otherwise specified in constructor.
97 >     * The default concurrency level for this table, used when not
98 >     * otherwise specified in a constructor.
99       */
100 <    static final float DEFAULT_LOAD_FACTOR = 0.75f;
100 >    static final int DEFAULT_CONCURRENCY_LEVEL = 16;
101  
102      /**
103 <     * The default number of concurrency control segments.
104 <     **/
105 <    static final int DEFAULT_SEGMENTS = 16;
103 >     * The maximum capacity, used if a higher value is implicitly
104 >     * specified by either of the constructors with arguments.  MUST
105 >     * be a power of two <= 1<<30 to ensure that entries are indexable
106 >     * using ints.
107 >     */
108 >    static final int MAXIMUM_CAPACITY = 1 << 30;
109  
110      /**
111       * The maximum number of segments to allow; used to bound
# Line 127 | Line 126 | public class ConcurrentHashMap<K, V> ext
126      /**
127       * Mask value for indexing into segments. The upper bits of a
128       * key's hash code are used to choose the segment.
129 <     **/
129 >     */
130      final int segmentMask;
131  
132      /**
133       * Shift value for indexing within segments.
134 <     **/
134 >     */
135      final int segmentShift;
136  
137      /**
138       * The segments, each of which is a specialized hash table
139       */
140 <    final Segment[] segments;
140 >    final Segment<K,V>[] segments;
141  
142      transient Set<K> keySet;
143      transient Set<Map.Entry<K,V>> entrySet;
# Line 147 | Line 146 | public class ConcurrentHashMap<K, V> ext
146      /* ---------------- Small Utilities -------------- */
147  
148      /**
149 <     * Returns a hash code for non-null Object x.
150 <     * Uses the same hash code spreader as most other java.util hash tables.
151 <     * @param x the object serving as a key
152 <     * @return the hash code
153 <     */
154 <    static int hash(Object x) {
155 <        int h = x.hashCode();
156 <        h += ~(h << 9);
157 <        h ^=  (h >>> 14);
158 <        h +=  (h << 4);
159 <        h ^=  (h >>> 10);
160 <        return h;
149 >     * Applies a supplemental hash function to a given hashCode, which
150 >     * defends against poor quality hash functions.  This is critical
151 >     * because ConcurrentHashMap uses power-of-two length hash tables,
152 >     * that otherwise encounter collisions for hashCodes that do not
153 >     * differ in lower or upper bits.
154 >     */
155 >    private static int hash(int h) {
156 >        // Spread bits to regularize both segment and index locations,
157 >        // using variant of single-word Wang/Jenkins hash.
158 >        h += (h <<  15) ^ 0xffffcd7d;
159 >        h ^= (h >>> 10);
160 >        h += (h <<   3);
161 >        h ^= (h >>>  6);
162 >        h += (h <<   2) + (h << 14);
163 >        return h ^ (h >>> 16);
164      }
165  
166      /**
# Line 167 | Line 169 | public class ConcurrentHashMap<K, V> ext
169       * @return the segment
170       */
171      final Segment<K,V> segmentFor(int hash) {
172 <        return (Segment<K,V>) segments[(hash >>> segmentShift) & segmentMask];
172 >        return segments[(hash >>> segmentShift) & segmentMask];
173      }
174  
175      /* ---------------- Inner Classes -------------- */
176  
177      /**
178       * ConcurrentHashMap list entry. Note that this is never exported
179 <     * out as a user-visible Map.Entry.
180 <     *
179 >     * out as a user-visible Map.Entry.
180 >     *
181       * Because the value field is volatile, not final, it is legal wrt
182       * the Java Memory Model for an unsynchronized reader to see null
183       * instead of initial value when read via a data race.  Although a
# Line 196 | Line 198 | public class ConcurrentHashMap<K, V> ext
198              this.next = next;
199              this.value = value;
200          }
201 +
202 +        @SuppressWarnings("unchecked")
203 +        static final <K,V> HashEntry<K,V>[] newArray(int i) {
204 +            return new HashEntry[i];
205 +        }
206      }
207  
208      /**
209       * Segments are specialized versions of hash tables.  This
210       * subclasses from ReentrantLock opportunistically, just to
211       * simplify some locking and avoid separate construction.
212 <     **/
212 >     */
213      static final class Segment<K,V> extends ReentrantLock implements Serializable {
214          /*
215           * Segments maintain a table of entry lists that are ALWAYS
# Line 245 | Line 252 | public class ConcurrentHashMap<K, V> ext
252  
253          /**
254           * The number of elements in this segment's region.
255 <         **/
255 >         */
256          transient volatile int count;
257  
258          /**
# Line 260 | Line 267 | public class ConcurrentHashMap<K, V> ext
267  
268          /**
269           * The table is rehashed when its size exceeds this threshold.
270 <         * (The value of this field is always (int)(capacity *
271 <         * loadFactor).)
270 >         * (The value of this field is always <tt>(int)(capacity *
271 >         * loadFactor)</tt>.)
272           */
273          transient int threshold;
274  
275          /**
276 <         * The per-segment table. Declared as a raw type, casted
270 <         * to HashEntry<K,V> on each use.
276 >         * The per-segment table.
277           */
278 <        transient volatile HashEntry[] table;
278 >        transient volatile HashEntry<K,V>[] table;
279  
280          /**
281           * The load factor for the hash table.  Even though this value
# Line 281 | Line 287 | public class ConcurrentHashMap<K, V> ext
287  
288          Segment(int initialCapacity, float lf) {
289              loadFactor = lf;
290 <            setTable(new HashEntry[initialCapacity]);
290 >            setTable(HashEntry.<K,V>newArray(initialCapacity));
291 >        }
292 >
293 >        @SuppressWarnings("unchecked")
294 >        static final <K,V> Segment<K,V>[] newArray(int i) {
295 >            return new Segment[i];
296          }
297  
298          /**
299 <         * Set table to new HashEntry array.
299 >         * Sets table to new HashEntry array.
300           * Call only while holding lock or in constructor.
301 <         **/
302 <        void setTable(HashEntry[] newTable) {
301 >         */
302 >        void setTable(HashEntry<K,V>[] newTable) {
303              threshold = (int)(newTable.length * loadFactor);
304              table = newTable;
305          }
306  
307          /**
308 <         * Return properly casted first entry of bin for given hash
308 >         * Returns properly casted first entry of bin for given hash.
309           */
310          HashEntry<K,V> getFirst(int hash) {
311 <            HashEntry[] tab = table;
312 <            return (HashEntry<K,V>) tab[hash & (tab.length - 1)];
311 >            HashEntry<K,V>[] tab = table;
312 >            return tab[hash & (tab.length - 1)];
313          }
314  
315          /**
316 <         * Read value field of an entry under lock. Called if value
316 >         * Reads value field of an entry under lock. Called if value
317           * field ever appears to be null. This is possible only if a
318           * compiler happens to reorder a HashEntry initialization with
319           * its table assignment, which is legal under memory model
# Line 349 | Line 360 | public class ConcurrentHashMap<K, V> ext
360  
361          boolean containsValue(Object value) {
362              if (count != 0) { // read-volatile
363 <                HashEntry[] tab = table;
363 >                HashEntry<K,V>[] tab = table;
364                  int len = tab.length;
365                  for (int i = 0 ; i < len; i++) {
366 <                    for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i];
356 <                         e != null ;
357 <                         e = e.next) {
366 >                    for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
367                          V v = e.value;
368                          if (v == null) // recheck
369                              v = readValueUnderLock(e);
# Line 409 | Line 418 | public class ConcurrentHashMap<K, V> ext
418                  int c = count;
419                  if (c++ > threshold) // ensure capacity
420                      rehash();
421 <                HashEntry[] tab = table;
421 >                HashEntry<K,V>[] tab = table;
422                  int index = hash & (tab.length - 1);
423 <                HashEntry<K,V> first = (HashEntry<K,V>) tab[index];
423 >                HashEntry<K,V> first = tab[index];
424                  HashEntry<K,V> e = first;
425                  while (e != null && (e.hash != hash || !key.equals(e.key)))
426                      e = e.next;
# Line 435 | Line 444 | public class ConcurrentHashMap<K, V> ext
444          }
445  
446          void rehash() {
447 <            HashEntry[] oldTable = table;            
447 >            HashEntry<K,V>[] oldTable = table;
448              int oldCapacity = oldTable.length;
449              if (oldCapacity >= MAXIMUM_CAPACITY)
450                  return;
# Line 454 | Line 463 | public class ConcurrentHashMap<K, V> ext
463               * right now.
464               */
465  
466 <            HashEntry[] newTable = new HashEntry[oldCapacity << 1];
466 >            HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1);
467              threshold = (int)(newTable.length * loadFactor);
468              int sizeMask = newTable.length - 1;
469              for (int i = 0; i < oldCapacity ; i++) {
470                  // We need to guarantee that any existing reads of old Map can
471                  //  proceed. So we cannot yet null out each bin.
472 <                HashEntry<K,V> e = (HashEntry<K,V>)oldTable[i];
472 >                HashEntry<K,V> e = oldTable[i];
473  
474                  if (e != null) {
475                      HashEntry<K,V> next = e.next;
# Line 488 | Line 497 | public class ConcurrentHashMap<K, V> ext
497                          // Clone all remaining nodes
498                          for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
499                              int k = p.hash & sizeMask;
500 <                            HashEntry<K,V> n = (HashEntry<K,V>)newTable[k];
500 >                            HashEntry<K,V> n = newTable[k];
501                              newTable[k] = new HashEntry<K,V>(p.key, p.hash,
502                                                               n, p.value);
503                          }
# Line 505 | Line 514 | public class ConcurrentHashMap<K, V> ext
514              lock();
515              try {
516                  int c = count - 1;
517 <                HashEntry[] tab = table;
517 >                HashEntry<K,V>[] tab = table;
518                  int index = hash & (tab.length - 1);
519 <                HashEntry<K,V> first = (HashEntry<K,V>)tab[index];
519 >                HashEntry<K,V> first = tab[index];
520                  HashEntry<K,V> e = first;
521                  while (e != null && (e.hash != hash || !key.equals(e.key)))
522                      e = e.next;
# Line 523 | Line 532 | public class ConcurrentHashMap<K, V> ext
532                          ++modCount;
533                          HashEntry<K,V> newFirst = e.next;
534                          for (HashEntry<K,V> p = first; p != e; p = p.next)
535 <                            newFirst = new HashEntry<K,V>(p.key, p.hash,  
535 >                            newFirst = new HashEntry<K,V>(p.key, p.hash,
536                                                            newFirst, p.value);
537                          tab[index] = newFirst;
538                          count = c; // write-volatile
# Line 539 | Line 548 | public class ConcurrentHashMap<K, V> ext
548              if (count != 0) {
549                  lock();
550                  try {
551 <                    HashEntry[] tab = table;
551 >                    HashEntry<K,V>[] tab = table;
552                      for (int i = 0; i < tab.length ; i++)
553                          tab[i] = null;
554                      ++modCount;
# Line 557 | Line 566 | public class ConcurrentHashMap<K, V> ext
566  
567      /**
568       * Creates a new, empty map with the specified initial
569 <     * capacity, load factor, and concurrency level.
569 >     * capacity, load factor and concurrency level.
570       *
571       * @param initialCapacity the initial capacity. The implementation
572       * performs internal sizing to accommodate this many elements.
573       * @param loadFactor  the load factor threshold, used to control resizing.
574 <     * Resizing may be performed when the average number of elements per
574 >     * Resizing may be performed when the average number of elements per
575       * bin exceeds this threshold.
576       * @param concurrencyLevel the estimated number of concurrently
577       * updating threads. The implementation performs internal sizing
578 <     * to try to accommodate this many threads.  
578 >     * to try to accommodate this many threads.
579       * @throws IllegalArgumentException if the initial capacity is
580       * negative or the load factor or concurrencyLevel are
581       * nonpositive.
# Line 588 | Line 597 | public class ConcurrentHashMap<K, V> ext
597          }
598          segmentShift = 32 - sshift;
599          segmentMask = ssize - 1;
600 <        this.segments = new Segment[ssize];
600 >        this.segments = Segment.newArray(ssize);
601  
602          if (initialCapacity > MAXIMUM_CAPACITY)
603              initialCapacity = MAXIMUM_CAPACITY;
# Line 604 | Line 613 | public class ConcurrentHashMap<K, V> ext
613      }
614  
615      /**
616 <     * Creates a new, empty map with the specified initial
617 <     * capacity,  and with default load factor (<tt>0.75f</tt>)
618 <     * and concurrencyLevel (<tt>16</tt>).
616 >     * Creates a new, empty map with the specified initial capacity
617 >     * and load factor and with the default concurrencyLevel (16).
618 >     *
619 >     * @param initialCapacity The implementation performs internal
620 >     * sizing to accommodate this many elements.
621 >     * @param loadFactor  the load factor threshold, used to control resizing.
622 >     * Resizing may be performed when the average number of elements per
623 >     * bin exceeds this threshold.
624 >     * @throws IllegalArgumentException if the initial capacity of
625 >     * elements is negative or the load factor is nonpositive
626 >     *
627 >     * @since 1.6
628 >     */
629 >    public ConcurrentHashMap(int initialCapacity, float loadFactor) {
630 >        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
631 >    }
632 >
633 >    /**
634 >     * Creates a new, empty map with the specified initial capacity,
635 >     * and with default load factor (0.75) and concurrencyLevel (16).
636       *
637       * @param initialCapacity the initial capacity. The implementation
638       * performs internal sizing to accommodate this many elements.
# Line 614 | Line 640 | public class ConcurrentHashMap<K, V> ext
640       * elements is negative.
641       */
642      public ConcurrentHashMap(int initialCapacity) {
643 <        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
643 >        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
644      }
645  
646      /**
647 <     * Creates a new, empty map with a default initial capacity
648 <     * (<tt>16</tt>), load factor (<tt>0.75f</tt>) and
623 <     * concurrencyLevel (<tt>16</tt>).
647 >     * Creates a new, empty map with a default initial capacity (16),
648 >     * load factor (0.75) and concurrencyLevel (16).
649       */
650      public ConcurrentHashMap() {
651 <        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
651 >        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
652      }
653  
654      /**
655 <     * Creates a new map with the same mappings as the given map.  The
656 <     * map is created with a capacity consistent with the default load
657 <     * factor (<tt>0.75f</tt>) and uses the default concurrencyLevel
658 <     * (<tt>16</tt>).
659 <     * @param t the map
655 >     * Creates a new map with the same mappings as the given map.
656 >     * The map is created with a capacity of 1.5 times the number
657 >     * of mappings in the given map or 16 (whichever is greater),
658 >     * and a default load factor (0.75) and concurrencyLevel (16).
659 >     *
660 >     * @param m the map
661       */
662 <    public ConcurrentHashMap(Map<? extends K, ? extends V> t) {
663 <        this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1,
662 >    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
663 >        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
664                        DEFAULT_INITIAL_CAPACITY),
665 <             DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
666 <        putAll(t);
665 >             DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
666 >        putAll(m);
667      }
668  
669 <    // inherit Map javadoc
669 >    /**
670 >     * Returns <tt>true</tt> if this map contains no key-value mappings.
671 >     *
672 >     * @return <tt>true</tt> if this map contains no key-value mappings
673 >     */
674      public boolean isEmpty() {
675 <        final Segment[] segments = this.segments;
675 >        final Segment<K,V>[] segments = this.segments;
676          /*
677           * We keep track of per-segment modCounts to avoid ABA
678           * problems in which an element in one segment was added and
# Line 657 | Line 687 | public class ConcurrentHashMap<K, V> ext
687          for (int i = 0; i < segments.length; ++i) {
688              if (segments[i].count != 0)
689                  return false;
690 <            else
690 >            else
691                  mcsum += mc[i] = segments[i].modCount;
692          }
693          // If mcsum happens to be zero, then we know we got a snapshot
# Line 666 | Line 696 | public class ConcurrentHashMap<K, V> ext
696          if (mcsum != 0) {
697              for (int i = 0; i < segments.length; ++i) {
698                  if (segments[i].count != 0 ||
699 <                    mc[i] != segments[i].modCount)
699 >                    mc[i] != segments[i].modCount)
700                      return false;
701              }
702          }
703          return true;
704      }
705  
706 <    // inherit Map javadoc
706 >    /**
707 >     * Returns the number of key-value mappings in this map.  If the
708 >     * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
709 >     * <tt>Integer.MAX_VALUE</tt>.
710 >     *
711 >     * @return the number of key-value mappings in this map
712 >     */
713      public int size() {
714 <        final Segment[] segments = this.segments;
714 >        final Segment<K,V>[] segments = this.segments;
715          long sum = 0;
716          long check = 0;
717          int[] mc = new int[segments.length];
# Line 698 | Line 734 | public class ConcurrentHashMap<K, V> ext
734                      }
735                  }
736              }
737 <            if (check == sum)
737 >            if (check == sum)
738                  break;
739          }
740          if (check != sum) { // Resort to locking all segments
741              sum = 0;
742 <            for (int i = 0; i < segments.length; ++i)
742 >            for (int i = 0; i < segments.length; ++i)
743                  segments[i].lock();
744 <            for (int i = 0; i < segments.length; ++i)
744 >            for (int i = 0; i < segments.length; ++i)
745                  sum += segments[i].count;
746 <            for (int i = 0; i < segments.length; ++i)
746 >            for (int i = 0; i < segments.length; ++i)
747                  segments[i].unlock();
748          }
749          if (sum > Integer.MAX_VALUE)
# Line 716 | Line 752 | public class ConcurrentHashMap<K, V> ext
752              return (int)sum;
753      }
754  
719
755      /**
756 <     * Returns the value to which the specified key is mapped in this table.
756 >     * Returns the value to which the specified key is mapped,
757 >     * or {@code null} if this map contains no mapping for the key.
758 >     *
759 >     * <p>More formally, if this map contains a mapping from a key
760 >     * {@code k} to a value {@code v} such that {@code key.equals(k)},
761 >     * then this method returns {@code v}; otherwise it returns
762 >     * {@code null}.  (There can be at most one such mapping.)
763       *
764 <     * @param   key   a key in the table.
724 <     * @return  the value to which the key is mapped in this table;
725 <     *          <tt>null</tt> if the key is not mapped to any value in
726 <     *          this table.
727 <     * @throws  NullPointerException  if the key is
728 <     *               <tt>null</tt>.
764 >     * @throws NullPointerException if the specified key is null
765       */
766      public V get(Object key) {
767 <        int hash = hash(key); // throws NullPointerException if key null
767 >        int hash = hash(key.hashCode());
768          return segmentFor(hash).get(key, hash);
769      }
770  
771      /**
772       * Tests if the specified object is a key in this table.
773       *
774 <     * @param   key   possible key.
775 <     * @return  <tt>true</tt> if and only if the specified object
776 <     *          is a key in this table, as determined by the
777 <     *          <tt>equals</tt> method; <tt>false</tt> otherwise.
778 <     * @throws  NullPointerException  if the key is
743 <     *               <tt>null</tt>.
774 >     * @param  key   possible key
775 >     * @return <tt>true</tt> if and only if the specified object
776 >     *         is a key in this table, as determined by the
777 >     *         <tt>equals</tt> method; <tt>false</tt> otherwise.
778 >     * @throws NullPointerException if the specified key is null
779       */
780      public boolean containsKey(Object key) {
781 <        int hash = hash(key); // throws NullPointerException if key null
781 >        int hash = hash(key.hashCode());
782          return segmentFor(hash).containsKey(key, hash);
783      }
784  
# Line 753 | Line 788 | public class ConcurrentHashMap<K, V> ext
788       * traversal of the hash table, and so is much slower than
789       * method <tt>containsKey</tt>.
790       *
791 <     * @param value value whose presence in this map is to be tested.
791 >     * @param value value whose presence in this map is to be tested
792       * @return <tt>true</tt> if this map maps one or more keys to the
793 <     * specified value.
794 <     * @throws  NullPointerException  if the value is <tt>null</tt>.
793 >     *         specified value
794 >     * @throws NullPointerException if the specified value is null
795       */
796      public boolean containsValue(Object value) {
797          if (value == null)
798              throw new NullPointerException();
799 <        
799 >
800          // See explanation of modCount use above
801  
802 <        final Segment[] segments = this.segments;
802 >        final Segment<K,V>[] segments = this.segments;
803          int[] mc = new int[segments.length];
804  
805          // Try a few times without locking
# Line 791 | Line 826 | public class ConcurrentHashMap<K, V> ext
826                  return false;
827          }
828          // Resort to locking all segments
829 <        for (int i = 0; i < segments.length; ++i)
829 >        for (int i = 0; i < segments.length; ++i)
830              segments[i].lock();
831          boolean found = false;
832          try {
# Line 802 | Line 837 | public class ConcurrentHashMap<K, V> ext
837                  }
838              }
839          } finally {
840 <            for (int i = 0; i < segments.length; ++i)
840 >            for (int i = 0; i < segments.length; ++i)
841                  segments[i].unlock();
842          }
843          return found;
# Line 811 | Line 846 | public class ConcurrentHashMap<K, V> ext
846      /**
847       * Legacy method testing if some key maps into the specified value
848       * in this table.  This method is identical in functionality to
849 <     * {@link #containsValue}, and  exists solely to ensure
849 >     * {@link #containsValue}, and exists solely to ensure
850       * full compatibility with class {@link java.util.Hashtable},
851       * which supported this method prior to introduction of the
852       * Java Collections framework.
853  
854 <     * @param      value   a value to search for.
855 <     * @return     <tt>true</tt> if and only if some key maps to the
856 <     *             <tt>value</tt> argument in this table as
857 <     *             determined by the <tt>equals</tt> method;
858 <     *             <tt>false</tt> otherwise.
859 <     * @throws  NullPointerException  if the value is <tt>null</tt>.
854 >     * @param  value a value to search for
855 >     * @return <tt>true</tt> if and only if some key maps to the
856 >     *         <tt>value</tt> argument in this table as
857 >     *         determined by the <tt>equals</tt> method;
858 >     *         <tt>false</tt> otherwise
859 >     * @throws NullPointerException if the specified value is null
860       */
861      public boolean contains(Object value) {
862          return containsValue(value);
863      }
864  
865      /**
866 <     * Maps the specified <tt>key</tt> to the specified
867 <     * <tt>value</tt> in this table. Neither the key nor the
833 <     * value can be <tt>null</tt>.
866 >     * Maps the specified key to the specified value in this table.
867 >     * Neither the key nor the value can be null.
868       *
869       * <p> The value can be retrieved by calling the <tt>get</tt> method
870       * with a key that is equal to the original key.
871       *
872 <     * @param      key     the table key.
873 <     * @param      value   the value.
874 <     * @return     the previous value of the specified key in this table,
875 <     *             or <tt>null</tt> if it did not have one.
876 <     * @throws  NullPointerException  if the key or value is
843 <     *               <tt>null</tt>.
872 >     * @param key key with which the specified value is to be associated
873 >     * @param value value to be associated with the specified key
874 >     * @return the previous value associated with <tt>key</tt>, or
875 >     *         <tt>null</tt> if there was no mapping for <tt>key</tt>
876 >     * @throws NullPointerException if the specified key or value is null
877       */
878      public V put(K key, V value) {
879          if (value == null)
880              throw new NullPointerException();
881 <        int hash = hash(key);
881 >        int hash = hash(key.hashCode());
882          return segmentFor(hash).put(key, hash, value, false);
883      }
884  
885      /**
886 <     * If the specified key is not already associated
887 <     * with a value, associate it with the given value.
888 <     * This is equivalent to
889 <     * <pre>
890 <     *   if (!map.containsKey(key))
858 <     *      return map.put(key, value);
859 <     *   else
860 <     *      return map.get(key);
861 <     * </pre>
862 <     * Except that the action is performed atomically.
863 <     * @param key key with which the specified value is to be associated.
864 <     * @param value value to be associated with the specified key.
865 <     * @return previous value associated with specified key, or <tt>null</tt>
866 <     *         if there was no mapping for key.
867 <     * @throws NullPointerException if the specified key or value is
868 <     *            <tt>null</tt>.
886 >     * {@inheritDoc}
887 >     *
888 >     * @return the previous value associated with the specified key,
889 >     *         or <tt>null</tt> if there was no mapping for the key
890 >     * @throws NullPointerException if the specified key or value is null
891       */
892      public V putIfAbsent(K key, V value) {
893          if (value == null)
894              throw new NullPointerException();
895 <        int hash = hash(key);
895 >        int hash = hash(key.hashCode());
896          return segmentFor(hash).put(key, hash, value, true);
897      }
898  
877
899      /**
900       * Copies all of the mappings from the specified map to this one.
880     *
901       * These mappings replace any mappings that this map had for any of the
902 <     * keys currently in the specified Map.
902 >     * keys currently in the specified map.
903       *
904 <     * @param t Mappings to be stored in this map.
904 >     * @param m mappings to be stored in this map
905       */
906 <    public void putAll(Map<? extends K, ? extends V> t) {
907 <        for (Iterator<? extends Map.Entry<? extends K, ? extends V>> it = (Iterator<? extends Map.Entry<? extends K, ? extends V>>) t.entrySet().iterator(); it.hasNext(); ) {
888 <            Entry<? extends K, ? extends V> e = it.next();
906 >    public void putAll(Map<? extends K, ? extends V> m) {
907 >        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
908              put(e.getKey(), e.getValue());
890        }
909      }
910  
911      /**
912 <     * Removes the key (and its corresponding value) from this
913 <     * table. This method does nothing if the key is not in the table.
912 >     * Removes the key (and its corresponding value) from this map.
913 >     * This method does nothing if the key is not in the map.
914       *
915 <     * @param   key   the key that needs to be removed.
916 <     * @return  the value to which the key had been mapped in this table,
917 <     *          or <tt>null</tt> if the key did not have a mapping.
918 <     * @throws  NullPointerException  if the key is
901 <     *               <tt>null</tt>.
915 >     * @param  key the key that needs to be removed
916 >     * @return the previous value associated with <tt>key</tt>, or
917 >     *         <tt>null</tt> if there was no mapping for <tt>key</tt>
918 >     * @throws NullPointerException if the specified key is null
919       */
920      public V remove(Object key) {
921 <        int hash = hash(key);
921 >        int hash = hash(key.hashCode());
922          return segmentFor(hash).remove(key, hash, null);
923      }
924  
925      /**
926 <     * Remove entry for key only if currently mapped to given value.
927 <     * Acts as
928 <     * <pre>
912 <     *  if (map.get(key).equals(value)) {
913 <     *     map.remove(key);
914 <     *     return true;
915 <     * } else return false;
916 <     * </pre>
917 <     * except that the action is performed atomically.
918 <     * @param key key with which the specified value is associated.
919 <     * @param value value associated with the specified key.
920 <     * @return true if the value was removed
921 <     * @throws NullPointerException if the specified key is
922 <     *            <tt>null</tt>.
926 >     * {@inheritDoc}
927 >     *
928 >     * @throws NullPointerException if the specified key is null
929       */
930      public boolean remove(Object key, Object value) {
931 <        int hash = hash(key);
931 >        int hash = hash(key.hashCode());
932 >        if (value == null)
933 >            return false;
934          return segmentFor(hash).remove(key, hash, value) != null;
935      }
936  
929
937      /**
938 <     * Replace entry for key only if currently mapped to given value.
939 <     * Acts as
940 <     * <pre>
934 <     *  if (map.get(key).equals(oldValue)) {
935 <     *     map.put(key, newValue);
936 <     *     return true;
937 <     * } else return false;
938 <     * </pre>
939 <     * except that the action is performed atomically.
940 <     * @param key key with which the specified value is associated.
941 <     * @param oldValue value expected to be associated with the specified key.
942 <     * @param newValue value to be associated with the specified key.
943 <     * @return true if the value was replaced
944 <     * @throws NullPointerException if the specified key or values are
945 <     * <tt>null</tt>.
938 >     * {@inheritDoc}
939 >     *
940 >     * @throws NullPointerException if any of the arguments are null
941       */
942      public boolean replace(K key, V oldValue, V newValue) {
943          if (oldValue == null || newValue == null)
944              throw new NullPointerException();
945 <        int hash = hash(key);
945 >        int hash = hash(key.hashCode());
946          return segmentFor(hash).replace(key, hash, oldValue, newValue);
947      }
948  
949      /**
950 <     * Replace entry for key only if currently mapped to some value.
951 <     * Acts as
952 <     * <pre>
953 <     *  if ((map.containsKey(key)) {
954 <     *     return map.put(key, value);
960 <     * } else return null;
961 <     * </pre>
962 <     * except that the action is performed atomically.
963 <     * @param key key with which the specified value is associated.
964 <     * @param value value to be associated with the specified key.
965 <     * @return previous value associated with specified key, or <tt>null</tt>
966 <     *         if there was no mapping for key.  
967 <     * @throws NullPointerException if the specified key or value is
968 <     *            <tt>null</tt>.
950 >     * {@inheritDoc}
951 >     *
952 >     * @return the previous value associated with the specified key,
953 >     *         or <tt>null</tt> if there was no mapping for the key
954 >     * @throws NullPointerException if the specified key or value is null
955       */
956      public V replace(K key, V value) {
957          if (value == null)
958              throw new NullPointerException();
959 <        int hash = hash(key);
959 >        int hash = hash(key.hashCode());
960          return segmentFor(hash).replace(key, hash, value);
961      }
962  
977
963      /**
964 <     * Removes all mappings from this map.
964 >     * Removes all of the mappings from this map.
965       */
966      public void clear() {
967          for (int i = 0; i < segments.length; ++i)
# Line 984 | Line 969 | public class ConcurrentHashMap<K, V> ext
969      }
970  
971      /**
972 <     * Returns a set view of the keys contained in this map.  The set is
973 <     * backed by the map, so changes to the map are reflected in the set, and
974 <     * vice-versa.  The set supports element removal, which removes the
975 <     * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
976 <     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
977 <     * <tt>clear</tt> operations.  It does not support the <tt>add</tt> or
972 >     * Returns a {@link Set} view of the keys contained in this map.
973 >     * The set is backed by the map, so changes to the map are
974 >     * reflected in the set, and vice-versa.  The set supports element
975 >     * removal, which removes the corresponding mapping from this map,
976 >     * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
977 >     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
978 >     * operations.  It does not support the <tt>add</tt> or
979       * <tt>addAll</tt> operations.
980 <     * The view's returned <tt>iterator</tt> is a "weakly consistent" iterator that
981 <     * will never throw {@link java.util.ConcurrentModificationException},
980 >     *
981 >     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
982 >     * that will never throw {@link ConcurrentModificationException},
983       * and guarantees to traverse elements as they existed upon
984       * construction of the iterator, and may (but is not guaranteed to)
985       * reflect any modifications subsequent to construction.
999     *
1000     * @return a set view of the keys contained in this map.
986       */
987      public Set<K> keySet() {
988          Set<K> ks = keySet;
989          return (ks != null) ? ks : (keySet = new KeySet());
990      }
991  
1007
992      /**
993 <     * Returns a collection view of the values contained in this map.  The
994 <     * collection is backed by the map, so changes to the map are reflected in
995 <     * the collection, and vice-versa.  The collection supports element
996 <     * removal, which removes the corresponding mapping from this map, via the
997 <     * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
998 <     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
999 <     * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
1000 <     * The view's returned <tt>iterator</tt> is a "weakly consistent" iterator that
1001 <     * will never throw {@link java.util.ConcurrentModificationException},
993 >     * Returns a {@link Collection} view of the values contained in this map.
994 >     * The collection is backed by the map, so changes to the map are
995 >     * reflected in the collection, and vice-versa.  The collection
996 >     * supports element removal, which removes the corresponding
997 >     * mapping from this map, via the <tt>Iterator.remove</tt>,
998 >     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
999 >     * <tt>retainAll</tt>, and <tt>clear</tt> operations.  It does not
1000 >     * support the <tt>add</tt> or <tt>addAll</tt> operations.
1001 >     *
1002 >     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
1003 >     * that will never throw {@link ConcurrentModificationException},
1004       * and guarantees to traverse elements as they existed upon
1005       * construction of the iterator, and may (but is not guaranteed to)
1006       * reflect any modifications subsequent to construction.
1021     *
1022     * @return a collection view of the values contained in this map.
1007       */
1008      public Collection<V> values() {
1009          Collection<V> vs = values;
1010          return (vs != null) ? vs : (values = new Values());
1011      }
1012  
1029
1013      /**
1014 <     * Returns a collection view of the mappings contained in this map.  Each
1015 <     * element in the returned collection is a <tt>Map.Entry</tt>.  The
1016 <     * collection is backed by the map, so changes to the map are reflected in
1017 <     * the collection, and vice-versa.  The collection supports element
1018 <     * removal, which removes the corresponding mapping from the map, via the
1019 <     * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
1020 <     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
1021 <     * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
1022 <     * The view's returned <tt>iterator</tt> is a "weakly consistent" iterator that
1023 <     * will never throw {@link java.util.ConcurrentModificationException},
1014 >     * Returns a {@link Set} view of the mappings contained in this map.
1015 >     * The set is backed by the map, so changes to the map are
1016 >     * reflected in the set, and vice-versa.  The set supports element
1017 >     * removal, which removes the corresponding mapping from the map,
1018 >     * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
1019 >     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
1020 >     * operations.  It does not support the <tt>add</tt> or
1021 >     * <tt>addAll</tt> operations.
1022 >     *
1023 >     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
1024 >     * that will never throw {@link ConcurrentModificationException},
1025       * and guarantees to traverse elements as they existed upon
1026       * construction of the iterator, and may (but is not guaranteed to)
1027       * reflect any modifications subsequent to construction.
1044     *
1045     * @return a collection view of the mappings contained in this map.
1028       */
1029      public Set<Map.Entry<K,V>> entrySet() {
1030          Set<Map.Entry<K,V>> es = entrySet;
1031 <        return (es != null) ? es : (entrySet = (Set<Map.Entry<K,V>>) (Set) new EntrySet());
1031 >        return (es != null) ? es : (entrySet = new EntrySet());
1032      }
1033  
1052
1034      /**
1035       * Returns an enumeration of the keys in this table.
1036       *
1037 <     * @return  an enumeration of the keys in this table.
1038 <     * @see     #keySet
1037 >     * @return an enumeration of the keys in this table
1038 >     * @see #keySet()
1039       */
1040      public Enumeration<K> keys() {
1041          return new KeyIterator();
# Line 1063 | Line 1044 | public class ConcurrentHashMap<K, V> ext
1044      /**
1045       * Returns an enumeration of the values in this table.
1046       *
1047 <     * @return  an enumeration of the values in this table.
1048 <     * @see     #values
1047 >     * @return an enumeration of the values in this table
1048 >     * @see #values()
1049       */
1050      public Enumeration<V> elements() {
1051          return new ValueIterator();
# Line 1075 | Line 1056 | public class ConcurrentHashMap<K, V> ext
1056      abstract class HashIterator {
1057          int nextSegmentIndex;
1058          int nextTableIndex;
1059 <        HashEntry[] currentTable;
1059 >        HashEntry<K,V>[] currentTable;
1060          HashEntry<K, V> nextEntry;
1061          HashEntry<K, V> lastReturned;
1062  
# Line 1092 | Line 1073 | public class ConcurrentHashMap<K, V> ext
1073                  return;
1074  
1075              while (nextTableIndex >= 0) {
1076 <                if ( (nextEntry = (HashEntry<K,V>)currentTable[nextTableIndex--]) != null)
1076 >                if ( (nextEntry = currentTable[nextTableIndex--]) != null)
1077                      return;
1078              }
1079  
1080              while (nextSegmentIndex >= 0) {
1081 <                Segment<K,V> seg = (Segment<K,V>)segments[nextSegmentIndex--];
1081 >                Segment<K,V> seg = segments[nextSegmentIndex--];
1082                  if (seg.count != 0) {
1083                      currentTable = seg.table;
1084                      for (int j = currentTable.length - 1; j >= 0; --j) {
1085 <                        if ( (nextEntry = (HashEntry<K,V>)currentTable[j]) != null) {
1085 >                        if ( (nextEntry = currentTable[j]) != null) {
1086                              nextTableIndex = j - 1;
1087                              return;
1088                          }
# Line 1128 | Line 1109 | public class ConcurrentHashMap<K, V> ext
1109          }
1110      }
1111  
1112 <    final class KeyIterator extends HashIterator implements Iterator<K>, Enumeration<K> {
1113 <        public K next() { return super.nextEntry().key; }
1112 >    final class KeyIterator
1113 >        extends HashIterator
1114 >        implements Iterator<K>, Enumeration<K>
1115 >    {
1116 >        public K next()        { return super.nextEntry().key; }
1117          public K nextElement() { return super.nextEntry().key; }
1118      }
1119  
1120 <    final class ValueIterator extends HashIterator implements Iterator<V>, Enumeration<V> {
1121 <        public V next() { return super.nextEntry().value; }
1120 >    final class ValueIterator
1121 >        extends HashIterator
1122 >        implements Iterator<V>, Enumeration<V>
1123 >    {
1124 >        public V next()        { return super.nextEntry().value; }
1125          public V nextElement() { return super.nextEntry().value; }
1126      }
1127  
1141    
1142
1128      /**
1129 <     * Entry iterator. Exported Entry objects must write-through
1130 <     * changes in setValue, even if the nodes have been cloned. So we
1146 <     * cannot return internal HashEntry objects. Instead, the iterator
1147 <     * itself acts as a forwarding pseudo-entry.
1129 >     * Custom Entry class used by EntryIterator.next(), that relays
1130 >     * setValue changes to the underlying map.
1131       */
1132 <    final class EntryIterator extends HashIterator implements Map.Entry<K,V>, Iterator<Entry<K,V>> {
1133 <        public Map.Entry<K,V> next() {
1134 <            nextEntry();
1135 <            return this;
1136 <        }
1154 <
1155 <        public K getKey() {
1156 <            if (lastReturned == null)
1157 <                throw new IllegalStateException("Entry was removed");
1158 <            return lastReturned.key;
1159 <        }
1160 <
1161 <        public V getValue() {
1162 <            if (lastReturned == null)
1163 <                throw new IllegalStateException("Entry was removed");
1164 <            return ConcurrentHashMap.this.get(lastReturned.key);
1165 <        }
1166 <
1167 <        public V setValue(V value) {
1168 <            if (lastReturned == null)
1169 <                throw new IllegalStateException("Entry was removed");
1170 <            return ConcurrentHashMap.this.put(lastReturned.key, value);
1171 <        }
1172 <
1173 <        public boolean equals(Object o) {
1174 <            // If not acting as entry, just use default.
1175 <            if (lastReturned == null)
1176 <                return super.equals(o);
1177 <            if (!(o instanceof Map.Entry))
1178 <                return false;
1179 <            Map.Entry e = (Map.Entry)o;
1180 <            return eq(getKey(), e.getKey()) && eq(getValue(), e.getValue());
1181 <        }
1182 <
1183 <        public int hashCode() {
1184 <            // If not acting as entry, just use default.
1185 <            if (lastReturned == null)
1186 <                return super.hashCode();
1187 <
1188 <            Object k = getKey();
1189 <            Object v = getValue();
1190 <            return ((k == null) ? 0 : k.hashCode()) ^
1191 <                   ((v == null) ? 0 : v.hashCode());
1132 >    final class WriteThroughEntry
1133 >        extends AbstractMap.SimpleEntry<K,V>
1134 >    {
1135 >        WriteThroughEntry(K k, V v) {
1136 >            super(k,v);
1137          }
1138  
1139 <        public String toString() {
1140 <            // If not acting as entry, just use default.
1141 <            if (lastReturned == null)
1142 <                return super.toString();
1143 <            else
1144 <                return getKey() + "=" + getValue();
1139 >        /**
1140 >         * Set our entry's value and write through to the map. The
1141 >         * value to return is somewhat arbitrary here. Since a
1142 >         * WriteThroughEntry does not necessarily track asynchronous
1143 >         * changes, the most recent "previous" value could be
1144 >         * different from what we return (or could even have been
1145 >         * removed in which case the put will re-establish). We do not
1146 >         * and cannot guarantee more.
1147 >         */
1148 >        public V setValue(V value) {
1149 >            if (value == null) throw new NullPointerException();
1150 >            V v = super.setValue(value);
1151 >            ConcurrentHashMap.this.put(getKey(), value);
1152 >            return v;
1153          }
1154 +    }
1155  
1156 <        boolean eq(Object o1, Object o2) {
1157 <            return (o1 == null ? o2 == null : o1.equals(o2));
1156 >    final class EntryIterator
1157 >        extends HashIterator
1158 >        implements Iterator<Entry<K,V>>
1159 >    {
1160 >        public Map.Entry<K,V> next() {
1161 >            HashEntry<K,V> e = super.nextEntry();
1162 >            return new WriteThroughEntry(e.key, e.value);
1163          }
1205
1164      }
1165  
1166      final class KeySet extends AbstractSet<K> {
# Line 1221 | Line 1179 | public class ConcurrentHashMap<K, V> ext
1179          public void clear() {
1180              ConcurrentHashMap.this.clear();
1181          }
1224        public Object[] toArray() {
1225            Collection<K> c = new ArrayList<K>();
1226            for (Iterator<K> i = iterator(); i.hasNext(); )
1227                c.add(i.next());
1228            return c.toArray();
1229        }
1230        public <T> T[] toArray(T[] a) {
1231            Collection<K> c = new ArrayList<K>();
1232            for (Iterator<K> i = iterator(); i.hasNext(); )
1233                c.add(i.next());
1234            return c.toArray(a);
1235        }
1182      }
1183  
1184      final class Values extends AbstractCollection<V> {
# Line 1248 | Line 1194 | public class ConcurrentHashMap<K, V> ext
1194          public void clear() {
1195              ConcurrentHashMap.this.clear();
1196          }
1251        public Object[] toArray() {
1252            Collection<V> c = new ArrayList<V>();
1253            for (Iterator<V> i = iterator(); i.hasNext(); )
1254                c.add(i.next());
1255            return c.toArray();
1256        }
1257        public <T> T[] toArray(T[] a) {
1258            Collection<V> c = new ArrayList<V>();
1259            for (Iterator<V> i = iterator(); i.hasNext(); )
1260                c.add(i.next());
1261            return c.toArray(a);
1262        }
1197      }
1198  
1199      final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
# Line 1269 | Line 1203 | public class ConcurrentHashMap<K, V> ext
1203          public boolean contains(Object o) {
1204              if (!(o instanceof Map.Entry))
1205                  return false;
1206 <            Map.Entry<K,V> e = (Map.Entry<K,V>)o;
1206 >            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1207              V v = ConcurrentHashMap.this.get(e.getKey());
1208              return v != null && v.equals(e.getValue());
1209          }
1210          public boolean remove(Object o) {
1211              if (!(o instanceof Map.Entry))
1212                  return false;
1213 <            Map.Entry<K,V> e = (Map.Entry<K,V>)o;
1213 >            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1214              return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
1215          }
1216          public int size() {
# Line 1285 | Line 1219 | public class ConcurrentHashMap<K, V> ext
1219          public void clear() {
1220              ConcurrentHashMap.this.clear();
1221          }
1288        public Object[] toArray() {
1289            // Since we don't ordinarily have distinct Entry objects, we
1290            // must pack elements using exportable SimpleEntry
1291            Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size());
1292            for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); )
1293                c.add(new SimpleEntry<K,V>(i.next()));
1294            return c.toArray();
1295        }
1296        public <T> T[] toArray(T[] a) {
1297            Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size());
1298            for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); )
1299                c.add(new SimpleEntry<K,V>(i.next()));
1300            return c.toArray(a);
1301        }
1302
1303    }
1304
1305    /**
1306     * This duplicates java.util.AbstractMap.SimpleEntry until this class
1307     * is made accessible.
1308     */
1309    static final class SimpleEntry<K,V> implements Entry<K,V> {
1310        K key;
1311        V value;
1312
1313        public SimpleEntry(K key, V value) {
1314            this.key   = key;
1315            this.value = value;
1316        }
1317
1318        public SimpleEntry(Entry<K,V> e) {
1319            this.key   = e.getKey();
1320            this.value = e.getValue();
1321        }
1322
1323        public K getKey() {
1324            return key;
1325        }
1326
1327        public V getValue() {
1328            return value;
1329        }
1330
1331        public V setValue(V value) {
1332            V oldValue = this.value;
1333            this.value = value;
1334            return oldValue;
1335        }
1336
1337        public boolean equals(Object o) {
1338            if (!(o instanceof Map.Entry))
1339                return false;
1340            Map.Entry e = (Map.Entry)o;
1341            return eq(key, e.getKey()) && eq(value, e.getValue());
1342        }
1343
1344        public int hashCode() {
1345            return ((key   == null)   ? 0 :   key.hashCode()) ^
1346                   ((value == null)   ? 0 : value.hashCode());
1347        }
1348
1349        public String toString() {
1350            return key + "=" + value;
1351        }
1352
1353        static boolean eq(Object o1, Object o2) {
1354            return (o1 == null ? o2 == null : o1.equals(o2));
1355        }
1222      }
1223  
1224      /* ---------------- Serialization Support -------------- */
1225  
1226      /**
1227 <     * Save the state of the <tt>ConcurrentHashMap</tt>
1228 <     * instance to a stream (i.e.,
1363 <     * serialize it).
1227 >     * Save the state of the <tt>ConcurrentHashMap</tt> instance to a
1228 >     * stream (i.e., serialize it).
1229       * @param s the stream
1230       * @serialData
1231       * the key (Object) and value (Object)
# Line 1371 | Line 1236 | public class ConcurrentHashMap<K, V> ext
1236          s.defaultWriteObject();
1237  
1238          for (int k = 0; k < segments.length; ++k) {
1239 <            Segment<K,V> seg = (Segment<K,V>)segments[k];
1239 >            Segment<K,V> seg = segments[k];
1240              seg.lock();
1241              try {
1242 <                HashEntry[] tab = seg.table;
1242 >                HashEntry<K,V>[] tab = seg.table;
1243                  for (int i = 0; i < tab.length; ++i) {
1244 <                    for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i]; e != null; e = e.next) {
1244 >                    for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
1245                          s.writeObject(e.key);
1246                          s.writeObject(e.value);
1247                      }
# Line 1390 | Line 1255 | public class ConcurrentHashMap<K, V> ext
1255      }
1256  
1257      /**
1258 <     * Reconstitute the <tt>ConcurrentHashMap</tt>
1259 <     * instance from a stream (i.e.,
1395 <     * deserialize it).
1258 >     * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a
1259 >     * stream (i.e., deserialize it).
1260       * @param s the stream
1261       */
1262      private void readObject(java.io.ObjectInputStream s)
# Line 1414 | Line 1278 | public class ConcurrentHashMap<K, V> ext
1278          }
1279      }
1280   }
1417

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines