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.70 by jsr166, Sat May 21 02:49:21 2005 UTC vs.
Revision 1.89 by dl, Tue Jun 6 11:17:58 2006 UTC

# Line 62 | Line 62 | import java.io.ObjectOutputStream;
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
# Line 137 | Line 137 | public class ConcurrentHashMap<K, V> ext
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 146 | 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 HashMap uses power-of two length hash tables, that
152 >     * otherwise encounter collisions for hashCodes that do not differ
153 >     * in lower bits.
154 >     */
155 >    static int hash(int h) {
156 >        // This function ensures that hashCodes that differ only by
157 >        // constant multiples at each bit position have a bounded
158 >        // number of collisions (approximately 8 at default load factor).
159 >        h ^= (h >>> 20) ^ (h >>> 12);
160 >        return h ^ (h >>> 7) ^ (h >>> 4);
161      }
162  
163      /**
# Line 166 | Line 166 | public class ConcurrentHashMap<K, V> ext
166       * @return the segment
167       */
168      final Segment<K,V> segmentFor(int hash) {
169 <        return (Segment<K,V>) segments[(hash >>> segmentShift) & segmentMask];
169 >        return segments[(hash >>> segmentShift) & segmentMask];
170      }
171  
172      /* ---------------- Inner Classes -------------- */
# Line 195 | Line 195 | public class ConcurrentHashMap<K, V> ext
195              this.next = next;
196              this.value = value;
197          }
198 +
199 +        @SuppressWarnings("unchecked")
200 +        static final <K,V> HashEntry<K,V>[] newArray(int i) {
201 +            return new HashEntry[i];
202 +        }
203      }
204  
205      /**
# Line 265 | Line 270 | public class ConcurrentHashMap<K, V> ext
270          transient int threshold;
271  
272          /**
273 <         * The per-segment table. Declared as a raw type, casted
269 <         * to HashEntry<K,V> on each use.
273 >         * The per-segment table.
274           */
275 <        transient volatile HashEntry[] table;
275 >        transient volatile HashEntry<K,V>[] table;
276  
277          /**
278           * The load factor for the hash table.  Even though this value
# Line 280 | Line 284 | public class ConcurrentHashMap<K, V> ext
284  
285          Segment(int initialCapacity, float lf) {
286              loadFactor = lf;
287 <            setTable(new HashEntry[initialCapacity]);
287 >            setTable(HashEntry.<K,V>newArray(initialCapacity));
288 >        }
289 >
290 >        @SuppressWarnings("unchecked")
291 >        static final <K,V> Segment<K,V>[] newArray(int i) {
292 >            return new Segment[i];
293          }
294  
295          /**
296           * Sets table to new HashEntry array.
297           * Call only while holding lock or in constructor.
298           */
299 <        void setTable(HashEntry[] newTable) {
299 >        void setTable(HashEntry<K,V>[] newTable) {
300              threshold = (int)(newTable.length * loadFactor);
301              table = newTable;
302          }
# Line 296 | Line 305 | public class ConcurrentHashMap<K, V> ext
305           * Returns properly casted first entry of bin for given hash.
306           */
307          HashEntry<K,V> getFirst(int hash) {
308 <            HashEntry[] tab = table;
309 <            return (HashEntry<K,V>) tab[hash & (tab.length - 1)];
308 >            HashEntry<K,V>[] tab = table;
309 >            return tab[hash & (tab.length - 1)];
310          }
311  
312          /**
# Line 348 | Line 357 | public class ConcurrentHashMap<K, V> ext
357  
358          boolean containsValue(Object value) {
359              if (count != 0) { // read-volatile
360 <                HashEntry[] tab = table;
360 >                HashEntry<K,V>[] tab = table;
361                  int len = tab.length;
362                  for (int i = 0 ; i < len; i++) {
363 <                    for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i];
355 <                         e != null ;
356 <                         e = e.next) {
363 >                    for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
364                          V v = e.value;
365                          if (v == null) // recheck
366                              v = readValueUnderLock(e);
# Line 408 | Line 415 | public class ConcurrentHashMap<K, V> ext
415                  int c = count;
416                  if (c++ > threshold) // ensure capacity
417                      rehash();
418 <                HashEntry[] tab = table;
418 >                HashEntry<K,V>[] tab = table;
419                  int index = hash & (tab.length - 1);
420 <                HashEntry<K,V> first = (HashEntry<K,V>) tab[index];
420 >                HashEntry<K,V> first = tab[index];
421                  HashEntry<K,V> e = first;
422                  while (e != null && (e.hash != hash || !key.equals(e.key)))
423                      e = e.next;
# Line 434 | Line 441 | public class ConcurrentHashMap<K, V> ext
441          }
442  
443          void rehash() {
444 <            HashEntry[] oldTable = table;
444 >            HashEntry<K,V>[] oldTable = table;
445              int oldCapacity = oldTable.length;
446              if (oldCapacity >= MAXIMUM_CAPACITY)
447                  return;
# Line 453 | Line 460 | public class ConcurrentHashMap<K, V> ext
460               * right now.
461               */
462  
463 <            HashEntry[] newTable = new HashEntry[oldCapacity << 1];
463 >            HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1);
464              threshold = (int)(newTable.length * loadFactor);
465              int sizeMask = newTable.length - 1;
466              for (int i = 0; i < oldCapacity ; i++) {
467                  // We need to guarantee that any existing reads of old Map can
468                  //  proceed. So we cannot yet null out each bin.
469 <                HashEntry<K,V> e = (HashEntry<K,V>)oldTable[i];
469 >                HashEntry<K,V> e = oldTable[i];
470  
471                  if (e != null) {
472                      HashEntry<K,V> next = e.next;
# Line 487 | Line 494 | public class ConcurrentHashMap<K, V> ext
494                          // Clone all remaining nodes
495                          for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
496                              int k = p.hash & sizeMask;
497 <                            HashEntry<K,V> n = (HashEntry<K,V>)newTable[k];
497 >                            HashEntry<K,V> n = newTable[k];
498                              newTable[k] = new HashEntry<K,V>(p.key, p.hash,
499                                                               n, p.value);
500                          }
# Line 504 | Line 511 | public class ConcurrentHashMap<K, V> ext
511              lock();
512              try {
513                  int c = count - 1;
514 <                HashEntry[] tab = table;
514 >                HashEntry<K,V>[] tab = table;
515                  int index = hash & (tab.length - 1);
516 <                HashEntry<K,V> first = (HashEntry<K,V>)tab[index];
516 >                HashEntry<K,V> first = tab[index];
517                  HashEntry<K,V> e = first;
518                  while (e != null && (e.hash != hash || !key.equals(e.key)))
519                      e = e.next;
# Line 538 | Line 545 | public class ConcurrentHashMap<K, V> ext
545              if (count != 0) {
546                  lock();
547                  try {
548 <                    HashEntry[] tab = table;
548 >                    HashEntry<K,V>[] tab = table;
549                      for (int i = 0; i < tab.length ; i++)
550                          tab[i] = null;
551                      ++modCount;
# Line 587 | Line 594 | public class ConcurrentHashMap<K, V> ext
594          }
595          segmentShift = 32 - sshift;
596          segmentMask = ssize - 1;
597 <        this.segments = new Segment[ssize];
597 >        this.segments = Segment.newArray(ssize);
598  
599          if (initialCapacity > MAXIMUM_CAPACITY)
600              initialCapacity = MAXIMUM_CAPACITY;
# Line 604 | Line 611 | public class ConcurrentHashMap<K, V> ext
611  
612      /**
613       * Creates a new, empty map with the specified initial capacity
614 <     * and load factor and with the default concurrencyLevel
608 <     * (<tt>16</tt>).
614 >     * and load factor and with the default concurrencyLevel (16).
615       *
616       * @param initialCapacity The implementation performs internal
617       * sizing to accommodate this many elements.
# Line 614 | Line 620 | public class ConcurrentHashMap<K, V> ext
620       * bin exceeds this threshold.
621       * @throws IllegalArgumentException if the initial capacity of
622       * elements is negative or the load factor is nonpositive
623 +     *
624 +     * @since 1.6
625       */
626      public ConcurrentHashMap(int initialCapacity, float loadFactor) {
627          this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
# Line 621 | Line 629 | public class ConcurrentHashMap<K, V> ext
629  
630      /**
631       * Creates a new, empty map with the specified initial capacity,
632 <     * and with default load factor (<tt>0.75f</tt>)
625 <     * and concurrencyLevel (<tt>16</tt>).
632 >     * and with default load factor (0.75) and concurrencyLevel (16).
633       *
634       * @param initialCapacity the initial capacity. The implementation
635       * performs internal sizing to accommodate this many elements.
# Line 634 | Line 641 | public class ConcurrentHashMap<K, V> ext
641      }
642  
643      /**
644 <     * Creates a new, empty map with a default initial capacity
645 <     * (<tt>16</tt>), load factor
639 <     * (<tt>0.75f</tt>), and concurrencyLevel
640 <     * (<tt>16</tt>).
644 >     * Creates a new, empty map with a default initial capacity (16),
645 >     * load factor (0.75) and concurrencyLevel (16).
646       */
647      public ConcurrentHashMap() {
648          this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
649      }
650  
651      /**
652 <     * Creates a new map with the same mappings as the given map.  The
653 <     * map is created with a capacity of 1.5 times the number of
654 <     * mappings in the given map or <tt>16</tt>
655 <     * (whichever is greater), and a default load factor
656 <     * (<tt>0.75f</tt>) and concurrencyLevel
652 <     * (<tt>16</tt>).
652 >     * Creates a new map with the same mappings as the given map.
653 >     * The map is created with a capacity of 1.5 times the number
654 >     * of mappings in the given map or 16 (whichever is greater),
655 >     * and a default load factor (0.75) and concurrencyLevel (16).
656 >     *
657       * @param m the map
658       */
659      public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
# Line 665 | Line 669 | public class ConcurrentHashMap<K, V> ext
669       * @return <tt>true</tt> if this map contains no key-value mappings
670       */
671      public boolean isEmpty() {
672 <        final Segment[] segments = this.segments;
672 >        final Segment<K,V>[] segments = this.segments;
673          /*
674           * We keep track of per-segment modCounts to avoid ABA
675           * problems in which an element in one segment was added and
# Line 704 | Line 708 | public class ConcurrentHashMap<K, V> ext
708       * @return the number of key-value mappings in this map
709       */
710      public int size() {
711 <        final Segment[] segments = this.segments;
711 >        final Segment<K,V>[] segments = this.segments;
712          long sum = 0;
713          long check = 0;
714          int[] mc = new int[segments.length];
# Line 746 | Line 750 | public class ConcurrentHashMap<K, V> ext
750      }
751  
752      /**
753 <     * Returns the value to which this map maps the specified key, or
754 <     * <tt>null</tt> if the map contains no mapping for the key.
753 >     * Returns the value to which the specified key is mapped,
754 >     * or {@code null} if this map contains no mapping for the key.
755 >     *
756 >     * <p>More formally, if this map contains a mapping from a key
757 >     * {@code k} to a value {@code v} such that {@code key.equals(k)},
758 >     * then this method returns {@code v}; otherwise it returns
759 >     * {@code null}.  (There can be at most one such mapping.)
760       *
752     * @param key key whose associated value is to be returned
753     * @return the value associated with <tt>key</tt> in this map, or
754     *         <tt>null</tt> if there is no mapping for <tt>key</tt>
761       * @throws NullPointerException if the specified key is null
762       */
763      public V get(Object key) {
764 <        int hash = hash(key); // throws NullPointerException if key null
764 >        int hash = hash(key.hashCode());
765          return segmentFor(hash).get(key, hash);
766      }
767  
# Line 769 | Line 775 | public class ConcurrentHashMap<K, V> ext
775       * @throws NullPointerException if the specified key is null
776       */
777      public boolean containsKey(Object key) {
778 <        int hash = hash(key); // throws NullPointerException if key null
778 >        int hash = hash(key.hashCode());
779          return segmentFor(hash).containsKey(key, hash);
780      }
781  
# Line 790 | Line 796 | public class ConcurrentHashMap<K, V> ext
796  
797          // See explanation of modCount use above
798  
799 <        final Segment[] segments = this.segments;
799 >        final Segment<K,V>[] segments = this.segments;
800          int[] mc = new int[segments.length];
801  
802          // Try a few times without locking
# Line 854 | Line 860 | public class ConcurrentHashMap<K, V> ext
860      }
861  
862      /**
863 <     * Maps the specified <tt>key</tt> to the specified
864 <     * <tt>value</tt> in this table. Neither the key nor the
859 <     * value can be <tt>null</tt>.
863 >     * Maps the specified key to the specified value in this table.
864 >     * Neither the key nor the value can be null.
865       *
866       * <p> The value can be retrieved by calling the <tt>get</tt> method
867       * with a key that is equal to the original key.
# Line 870 | Line 875 | public class ConcurrentHashMap<K, V> ext
875      public V put(K key, V value) {
876          if (value == null)
877              throw new NullPointerException();
878 <        int hash = hash(key);
878 >        int hash = hash(key.hashCode());
879          return segmentFor(hash).put(key, hash, value, false);
880      }
881  
# Line 884 | Line 889 | public class ConcurrentHashMap<K, V> ext
889      public V putIfAbsent(K key, V value) {
890          if (value == null)
891              throw new NullPointerException();
892 <        int hash = hash(key);
892 >        int hash = hash(key.hashCode());
893          return segmentFor(hash).put(key, hash, value, true);
894      }
895  
# Line 896 | Line 901 | public class ConcurrentHashMap<K, V> ext
901       * @param m mappings to be stored in this map
902       */
903      public void putAll(Map<? extends K, ? extends V> m) {
904 <        for (Iterator<? extends Map.Entry<? extends K, ? extends V>> it = (Iterator<? extends Map.Entry<? extends K, ? extends V>>) m.entrySet().iterator(); it.hasNext(); ) {
900 <            Entry<? extends K, ? extends V> e = it.next();
904 >        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
905              put(e.getKey(), e.getValue());
902        }
906      }
907  
908      /**
# Line 908 | Line 911 | public class ConcurrentHashMap<K, V> ext
911       *
912       * @param  key the key that needs to be removed
913       * @return the previous value associated with <tt>key</tt>, or
914 <     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
914 >     *         <tt>null</tt> if there was no mapping for <tt>key</tt>
915       * @throws NullPointerException if the specified key is null
916       */
917      public V remove(Object key) {
918 <        int hash = hash(key);
918 >        int hash = hash(key.hashCode());
919          return segmentFor(hash).remove(key, hash, null);
920      }
921  
# Line 922 | Line 925 | public class ConcurrentHashMap<K, V> ext
925       * @throws NullPointerException if the specified key is null
926       */
927      public boolean remove(Object key, Object value) {
928 +        int hash = hash(key.hashCode());
929          if (value == null)
930              return false;
927        int hash = hash(key);
931          return segmentFor(hash).remove(key, hash, value) != null;
932      }
933  
# Line 936 | Line 939 | public class ConcurrentHashMap<K, V> ext
939      public boolean replace(K key, V oldValue, V newValue) {
940          if (oldValue == null || newValue == null)
941              throw new NullPointerException();
942 <        int hash = hash(key);
942 >        int hash = hash(key.hashCode());
943          return segmentFor(hash).replace(key, hash, oldValue, newValue);
944      }
945  
# Line 950 | Line 953 | public class ConcurrentHashMap<K, V> ext
953      public V replace(K key, V value) {
954          if (value == null)
955              throw new NullPointerException();
956 <        int hash = hash(key);
956 >        int hash = hash(key.hashCode());
957          return segmentFor(hash).replace(key, hash, value);
958      }
959  
# Line 1050 | Line 1053 | public class ConcurrentHashMap<K, V> ext
1053      abstract class HashIterator {
1054          int nextSegmentIndex;
1055          int nextTableIndex;
1056 <        HashEntry[] currentTable;
1056 >        HashEntry<K,V>[] currentTable;
1057          HashEntry<K, V> nextEntry;
1058          HashEntry<K, V> lastReturned;
1059  
# Line 1067 | Line 1070 | public class ConcurrentHashMap<K, V> ext
1070                  return;
1071  
1072              while (nextTableIndex >= 0) {
1073 <                if ( (nextEntry = (HashEntry<K,V>)currentTable[nextTableIndex--]) != null)
1073 >                if ( (nextEntry = currentTable[nextTableIndex--]) != null)
1074                      return;
1075              }
1076  
1077              while (nextSegmentIndex >= 0) {
1078 <                Segment<K,V> seg = (Segment<K,V>)segments[nextSegmentIndex--];
1078 >                Segment<K,V> seg = segments[nextSegmentIndex--];
1079                  if (seg.count != 0) {
1080                      currentTable = seg.table;
1081                      for (int j = currentTable.length - 1; j >= 0; --j) {
1082 <                        if ( (nextEntry = (HashEntry<K,V>)currentTable[j]) != null) {
1082 >                        if ( (nextEntry = currentTable[j]) != null) {
1083                              nextTableIndex = j - 1;
1084                              return;
1085                          }
# Line 1103 | Line 1106 | public class ConcurrentHashMap<K, V> ext
1106          }
1107      }
1108  
1109 <    final class KeyIterator extends HashIterator implements Iterator<K>, Enumeration<K> {
1110 <        public K next() { return super.nextEntry().key; }
1109 >    final class KeyIterator
1110 >        extends HashIterator
1111 >        implements Iterator<K>, Enumeration<K>
1112 >    {
1113 >        public K next()        { return super.nextEntry().key; }
1114          public K nextElement() { return super.nextEntry().key; }
1115      }
1116  
1117 <    final class ValueIterator extends HashIterator implements Iterator<V>, Enumeration<V> {
1118 <        public V next() { return super.nextEntry().value; }
1117 >    final class ValueIterator
1118 >        extends HashIterator
1119 >        implements Iterator<V>, Enumeration<V>
1120 >    {
1121 >        public V next()        { return super.nextEntry().value; }
1122          public V nextElement() { return super.nextEntry().value; }
1123      }
1124  
1116
1117
1125      /**
1126 <     * Entry iterator. Exported Entry objects must write-through
1127 <     * changes in setValue, even if the nodes have been cloned. So we
1121 <     * cannot return internal HashEntry objects. Instead, the iterator
1122 <     * itself acts as a forwarding pseudo-entry.
1126 >     * Custom Entry class used by EntryIterator.next(), that relays
1127 >     * setValue changes to the underlying map.
1128       */
1129 <    final class EntryIterator extends HashIterator implements Map.Entry<K,V>, Iterator<Entry<K,V>> {
1130 <        public Map.Entry<K,V> next() {
1131 <            nextEntry();
1132 <            return this;
1133 <        }
1129 <
1130 <        public K getKey() {
1131 <            if (lastReturned == null)
1132 <                throw new IllegalStateException("Entry was removed");
1133 <            return lastReturned.key;
1134 <        }
1135 <
1136 <        public V getValue() {
1137 <            if (lastReturned == null)
1138 <                throw new IllegalStateException("Entry was removed");
1139 <            return ConcurrentHashMap.this.get(lastReturned.key);
1140 <        }
1141 <
1142 <        public V setValue(V value) {
1143 <            if (lastReturned == null)
1144 <                throw new IllegalStateException("Entry was removed");
1145 <            return ConcurrentHashMap.this.put(lastReturned.key, value);
1129 >    final class WriteThroughEntry
1130 >        extends AbstractMap.SimpleEntry<K,V>
1131 >    {
1132 >        WriteThroughEntry(K k, V v) {
1133 >            super(k,v);
1134          }
1135  
1136 <        public boolean equals(Object o) {
1137 <            // If not acting as entry, just use default.
1138 <            if (lastReturned == null)
1139 <                return super.equals(o);
1140 <            if (!(o instanceof Map.Entry))
1141 <                return false;
1142 <            Map.Entry e = (Map.Entry)o;
1143 <            return eq(getKey(), e.getKey()) && eq(getValue(), e.getValue());
1144 <        }
1145 <
1146 <        public int hashCode() {
1147 <            // If not acting as entry, just use default.
1148 <            if (lastReturned == null)
1149 <                return super.hashCode();
1162 <
1163 <            Object k = getKey();
1164 <            Object v = getValue();
1165 <            return ((k == null) ? 0 : k.hashCode()) ^
1166 <                   ((v == null) ? 0 : v.hashCode());
1167 <        }
1168 <
1169 <        public String toString() {
1170 <            // If not acting as entry, just use default.
1171 <            if (lastReturned == null)
1172 <                return super.toString();
1173 <            else
1174 <                return getKey() + "=" + getValue();
1136 >        /**
1137 >         * Set our entry's value and write through to the map. The
1138 >         * value to return is somewhat arbitrary here. Since a
1139 >         * WriteThroughEntry does not necessarily track asynchronous
1140 >         * changes, the most recent "previous" value could be
1141 >         * different from what we return (or could even have been
1142 >         * removed in which case the put will re-establish). We do not
1143 >         * and cannot guarantee more.
1144 >         */
1145 >        public V setValue(V value) {
1146 >            if (value == null) throw new NullPointerException();
1147 >            V v = super.setValue(value);
1148 >            ConcurrentHashMap.this.put(getKey(), value);
1149 >            return v;
1150          }
1151 +    }
1152  
1153 <        boolean eq(Object o1, Object o2) {
1154 <            return (o1 == null ? o2 == null : o1.equals(o2));
1153 >    final class EntryIterator
1154 >        extends HashIterator
1155 >        implements Iterator<Entry<K,V>>
1156 >    {
1157 >        public Map.Entry<K,V> next() {
1158 >            HashEntry<K,V> e = super.nextEntry();
1159 >            return new WriteThroughEntry(e.key, e.value);
1160          }
1180
1161      }
1162  
1163      final class KeySet extends AbstractSet<K> {
# Line 1196 | Line 1176 | public class ConcurrentHashMap<K, V> ext
1176          public void clear() {
1177              ConcurrentHashMap.this.clear();
1178          }
1199        public Object[] toArray() {
1200            Collection<K> c = new ArrayList<K>();
1201            for (Iterator<K> i = iterator(); i.hasNext(); )
1202                c.add(i.next());
1203            return c.toArray();
1204        }
1205        public <T> T[] toArray(T[] a) {
1206            Collection<K> c = new ArrayList<K>();
1207            for (Iterator<K> i = iterator(); i.hasNext(); )
1208                c.add(i.next());
1209            return c.toArray(a);
1210        }
1179      }
1180  
1181      final class Values extends AbstractCollection<V> {
# Line 1223 | Line 1191 | public class ConcurrentHashMap<K, V> ext
1191          public void clear() {
1192              ConcurrentHashMap.this.clear();
1193          }
1226        public Object[] toArray() {
1227            Collection<V> c = new ArrayList<V>();
1228            for (Iterator<V> i = iterator(); i.hasNext(); )
1229                c.add(i.next());
1230            return c.toArray();
1231        }
1232        public <T> T[] toArray(T[] a) {
1233            Collection<V> c = new ArrayList<V>();
1234            for (Iterator<V> i = iterator(); i.hasNext(); )
1235                c.add(i.next());
1236            return c.toArray(a);
1237        }
1194      }
1195  
1196      final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
# Line 1244 | Line 1200 | public class ConcurrentHashMap<K, V> ext
1200          public boolean contains(Object o) {
1201              if (!(o instanceof Map.Entry))
1202                  return false;
1203 <            Map.Entry<K,V> e = (Map.Entry<K,V>)o;
1203 >            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1204              V v = ConcurrentHashMap.this.get(e.getKey());
1205              return v != null && v.equals(e.getValue());
1206          }
1207          public boolean remove(Object o) {
1208              if (!(o instanceof Map.Entry))
1209                  return false;
1210 <            Map.Entry<K,V> e = (Map.Entry<K,V>)o;
1210 >            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1211              return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
1212          }
1213          public int size() {
# Line 1260 | Line 1216 | public class ConcurrentHashMap<K, V> ext
1216          public void clear() {
1217              ConcurrentHashMap.this.clear();
1218          }
1263        public Object[] toArray() {
1264            // Since we don't ordinarily have distinct Entry objects, we
1265            // must pack elements using exportable SimpleEntry
1266            Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size());
1267            for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); )
1268                c.add(new AbstractMap.SimpleEntry<K,V>(i.next()));
1269            return c.toArray();
1270        }
1271        public <T> T[] toArray(T[] a) {
1272            Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size());
1273            for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); )
1274                c.add(new AbstractMap.SimpleEntry<K,V>(i.next()));
1275            return c.toArray(a);
1276        }
1277
1219      }
1220  
1221      /* ---------------- Serialization Support -------------- */
# Line 1292 | Line 1233 | public class ConcurrentHashMap<K, V> ext
1233          s.defaultWriteObject();
1234  
1235          for (int k = 0; k < segments.length; ++k) {
1236 <            Segment<K,V> seg = (Segment<K,V>)segments[k];
1236 >            Segment<K,V> seg = segments[k];
1237              seg.lock();
1238              try {
1239 <                HashEntry[] tab = seg.table;
1239 >                HashEntry<K,V>[] tab = seg.table;
1240                  for (int i = 0; i < tab.length; ++i) {
1241 <                    for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i]; e != null; e = e.next) {
1241 >                    for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
1242                          s.writeObject(e.key);
1243                          s.writeObject(e.value);
1244                      }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines