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.8 by dl, Tue Jun 24 14:34:47 2003 UTC vs.
Revision 1.15 by tim, Wed Aug 6 18:22:09 2003 UTC

# Line 5 | Line 5
5   */
6  
7   package java.util.concurrent;
8 <
8 > import java.util.concurrent.locks.*;
9   import java.util.*;
10   import java.io.Serializable;
11   import java.io.IOException;
# Line 22 | Line 22 | import java.io.ObjectOutputStream;
22   * entire table in a way that prevents all access.  This class is
23   * fully interoperable with Hashtable in programs that rely on its
24   * thread safety but not on its synchronization details.
25 < *  
25 > *
26   * <p> Retrieval operations (including <tt>get</tt>) ordinarily
27   * overlap with update operations (including <tt>put</tt> and
28   * <tt>remove</tt>). Retrievals reflect the results of the most
# Line 62 | Line 62 | public class ConcurrentHashMap<K, V> ext
62       */
63  
64      /* ---------------- Constants -------------- */
65 <    
65 >
66      /**
67       * The default initial number of table slots for this table (32).
68       * Used when not otherwise specified in constructor.
69       */
70 <    private static int DEFAULT_INITIAL_CAPACITY = 16;
70 >    private static int DEFAULT_INITIAL_CAPACITY = 16;
71  
72      /**
73       * The maximum capacity, used if a higher value is implicitly
# Line 75 | Line 75 | public class ConcurrentHashMap<K, V> ext
75       * be a power of two <= 1<<30.
76       */
77      static final int MAXIMUM_CAPACITY = 1 << 30;
78 <  
78 >
79      /**
80       * The default load factor for this table.  Used when not
81       * otherwise specified in constructor.
82       */
83 <    static final float DEFAULT_LOAD_FACTOR = 0.75f;
83 >    static final float DEFAULT_LOAD_FACTOR = 0.75f;
84  
85      /**
86       * The default number of concurrency control segments.
# Line 90 | Line 90 | public class ConcurrentHashMap<K, V> ext
90      /* ---------------- Fields -------------- */
91  
92      /**
93 <     * Mask value for indexing into segments. The lower bits of a
94 <     * key's hash code are used to choose the segment, and the
95 <     * remaining bits are used as the placement hashcode used within
96 <     * the segment.
93 >     * Mask value for indexing into segments. The upper bits of a
94 >     * key's hash code are used to choose the segment.
95       **/
96      private final int segmentMask;
97  
# Line 105 | Line 103 | public class ConcurrentHashMap<K, V> ext
103      /**
104       * The segments, each of which is a specialized hash table
105       */
106 <    private final Segment<K,V>[] segments;
106 >    private final Segment[] segments;
107  
108      private transient Set<K> keySet;
109 <    private transient Set/*<Map.Entry<K,V>>*/ entrySet;
109 >    private transient Set<Map.Entry<K,V>> entrySet;
110      private transient Collection<V> values;
111  
112      /* ---------------- Small Utilities -------------- */
113  
114      /**
115 <     * Return a hash code for non-null Object x.  
115 >     * Return a hash code for non-null Object x.
116       * Uses the same hash code spreader as most other j.u hash tables.
117       * @param x the object serving as a key
118       * @return the hash code
# Line 128 | Line 126 | public class ConcurrentHashMap<K, V> ext
126          return h;
127      }
128  
131    /**
132     * Check for equality of non-null references x and y.
133     **/
134    private static boolean eq(Object x, Object y) {
135        return x == y || x.equals(y);
136    }
137
138    /**
139     * Return index for hash code h in table of given length.
140     */
141    private static int indexFor(int h, int length) {
142        return h & (length-1);
143    }
144
129      /**
130       * Return the segment that should be used for key with given hash
131       */
132      private Segment<K,V> segmentFor(int hash) {
133 <        return segments[hash & segmentMask];
150 <    }
151 <
152 <    /**
153 <     * Strip the segment index from hash code to use as a per-segment hash.
154 <     */
155 <    private int segmentHashFor(int hash) {
156 <        return hash >>> segmentShift;
133 >        return (Segment<K,V>) segments[(hash >>> segmentShift) & segmentMask];
134      }
135  
136      /* ---------------- Inner Classes -------------- */
# Line 193 | Line 170 | public class ConcurrentHashMap<K, V> ext
170           *   - All unsynchronized read operations must first read the
171           *     "count" field, and should not look at table entries if
172           *     it is 0.
173 <         *    
173 >         *
174           *   - All synchronized write operations should write to
175           *     the "count" field after updating. The operations must not
176           *     take any action that could even momentarily cause
# Line 207 | Line 184 | public class ConcurrentHashMap<K, V> ext
184           * As a guide, all critical volatile reads and writes are marked
185           * in code comments.
186           */
187 <        
187 >
188          /**
189           * The number of elements in this segment's region.
190           **/
# Line 223 | Line 200 | public class ConcurrentHashMap<K, V> ext
200          /**
201           * The per-segment table
202           */
203 <        transient HashEntry<K,V>[] table;
203 >        transient HashEntry[] table;
204  
205          /**
206           * The load factor for the hash table.  Even though this value
# Line 235 | Line 212 | public class ConcurrentHashMap<K, V> ext
212  
213          Segment(int initialCapacity, float lf) {
214              loadFactor = lf;
215 <            setTable(new HashEntry<K,V>[initialCapacity]);
215 >            setTable(new HashEntry[initialCapacity]);
216          }
217  
218          /**
219 <         * Set table to new HashEntry array.
219 >         * Set table to new HashEntry array.
220           * Call only while holding lock or in constructor.
221           **/
222 <        private void setTable(HashEntry<K,V>[] newTable) {
222 >        private void setTable(HashEntry[] newTable) {
223              table = newTable;
224              threshold = (int)(newTable.length * loadFactor);
225              count = count; // write-volatile
226 <        }    
226 >        }
227  
228          /* Specialized implementations of map methods */
229 <        
230 <        V get(K key, int hash) {
229 >
230 >        V get(K key, int hash) {
231              if (count != 0) { // read-volatile
232 <                HashEntry<K,V>[] tab = table;
233 <                int index = indexFor(hash, tab.length);
234 <                HashEntry<K,V> e = tab[index];
232 >                HashEntry[] tab = table;
233 >                int index = hash & (tab.length - 1);
234 >                HashEntry<K,V> e = (HashEntry<K,V>) tab[index];
235                  while (e != null) {
236 <                    if (e.hash == hash && eq(key, e.key))
236 >                    if (e.hash == hash && key.equals(e.key))
237                          return e.value;
238                      e = e.next;
239                  }
# Line 266 | Line 243 | public class ConcurrentHashMap<K, V> ext
243  
244          boolean containsKey(Object key, int hash) {
245              if (count != 0) { // read-volatile
246 <                HashEntry<K,V>[] tab = table;
247 <                int index = indexFor(hash, tab.length);
248 <                HashEntry<K,V> e = tab[index];
246 >                HashEntry[] tab = table;
247 >                int index = hash & (tab.length - 1);
248 >                HashEntry<K,V> e = (HashEntry<K,V>) tab[index];
249                  while (e != null) {
250 <                    if (e.hash == hash && eq(key, e.key))
250 >                    if (e.hash == hash && key.equals(e.key))
251                          return true;
252                      e = e.next;
253                  }
254              }
255              return false;
256          }
257 <        
257 >
258          boolean containsValue(Object value) {
259              if (count != 0) { // read-volatile
260 <                HashEntry<K,V> tab[] = table;
260 >                HashEntry[] tab = table;
261                  int len = tab.length;
262 <                for (int i = 0 ; i < len; i++)
263 <                    for (HashEntry<K,V> e = tab[i] ; e != null ; e = e.next)
262 >                for (int i = 0 ; i < len; i++)
263 >                    for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i] ; e != null ; e = e.next)
264                          if (value.equals(e.value))
265                              return true;
266              }
267              return false;
268          }
269  
270 <        V put(K key, int hash, V value, boolean onlyIfAbsent) {
270 >        V put(K key, int hash, V value, boolean onlyIfAbsent) {
271              lock();
272              try {
273 <                HashEntry<K,V>[] tab = table;
274 <                int index = indexFor(hash, tab.length);
275 <                HashEntry<K,V> first = tab[index];
276 <                
277 <                for (HashEntry<K,V> e = first; e != null; e = e.next) {
278 <                    if (e.hash == hash && eq(key, e.key)) {
279 <                        V oldValue = e.value;
273 >                int c = count;
274 >                HashEntry[] tab = table;
275 >                int index = hash & (tab.length - 1);
276 >                HashEntry<K,V> first = (HashEntry<K,V>) tab[index];
277 >
278 >                for (HashEntry<K,V> e = first; e != null; e = (HashEntry<K,V>) e.next) {
279 >                    if (e.hash == hash && key.equals(e.key)) {
280 >                        V oldValue = e.value;
281                          if (!onlyIfAbsent)
282                              e.value = value;
283 <                        count = count; // write-volatile
283 >                        count = c; // write-volatile
284                          return oldValue;
285                      }
286                  }
287 <                
287 >
288                  tab[index] = new HashEntry<K,V>(hash, key, value, first);
289 <                if (++count > threshold) // write-volatile
290 <                    rehash();
289 >                ++c;
290 >                count = c; // write-volatile
291 >                if (c > threshold)
292 >                    setTable(rehash(tab));
293                  return null;
294              }
295              finally {
# Line 317 | Line 297 | public class ConcurrentHashMap<K, V> ext
297              }
298          }
299  
300 <        private void rehash() {
321 <            HashEntry<K,V>[] oldTable = table;
300 >        private HashEntry[] rehash(HashEntry[] oldTable) {
301              int oldCapacity = oldTable.length;
302              if (oldCapacity >= MAXIMUM_CAPACITY)
303 <                return;
303 >                return oldTable;
304  
305              /*
306               * Reclassify nodes in each list to new Map.  Because we are
# Line 336 | Line 315 | public class ConcurrentHashMap<K, V> ext
315               * reader thread that may be in the midst of traversing table
316               * right now.
317               */
318 <            
319 <            HashEntry<K,V>[] newTable = new HashEntry<K,V>[oldCapacity << 1];
318 >
319 >            HashEntry[] newTable = new HashEntry[oldCapacity << 1];
320              int sizeMask = newTable.length - 1;
321              for (int i = 0; i < oldCapacity ; i++) {
322                  // We need to guarantee that any existing reads of old Map can
323 <                //  proceed. So we cannot yet null out each bin.  
324 <                HashEntry<K,V> e = oldTable[i];
325 <                
323 >                //  proceed. So we cannot yet null out each bin.
324 >                HashEntry<K,V> e = (HashEntry<K,V>)oldTable[i];
325 >
326                  if (e != null) {
327                      HashEntry<K,V> next = e.next;
328                      int idx = e.hash & sizeMask;
329 <                    
329 >
330                      //  Single node on list
331 <                    if (next == null)
331 >                    if (next == null)
332                          newTable[idx] = e;
333 <                    
334 <                    else {    
333 >
334 >                    else {
335                          // Reuse trailing consecutive sequence at same slot
336                          HashEntry<K,V> lastRun = e;
337                          int lastIdx = idx;
338 <                        for (HashEntry<K,V> last = next;
339 <                             last != null;
338 >                        for (HashEntry<K,V> last = next;
339 >                             last != null;
340                               last = last.next) {
341                              int k = last.hash & sizeMask;
342                              if (k != lastIdx) {
# Line 366 | Line 345 | public class ConcurrentHashMap<K, V> ext
345                              }
346                          }
347                          newTable[lastIdx] = lastRun;
348 <                        
348 >
349                          // Clone all remaining nodes
350                          for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
351                              int k = p.hash & sizeMask;
352 <                            newTable[k] = new HashEntry<K,V>(p.hash,
353 <                                                             p.key,
354 <                                                             p.value,
355 <                                                             newTable[k]);
352 >                            newTable[k] = new HashEntry<K,V>(p.hash,
353 >                                                             p.key,
354 >                                                             p.value,
355 >                                                             (HashEntry<K,V>) newTable[k]);
356                          }
357                      }
358                  }
359              }
360 <            setTable(newTable);
360 >            return newTable;
361          }
362  
363          /**
364           * Remove; match on key only if value null, else match both.
365           */
366          V remove(Object key, int hash, Object value) {
367 <            lock();
367 >            lock();
368              try {
369 +                int c = count;
370                  HashEntry[] tab = table;
371 <                int index = indexFor(hash, tab.length);
372 <                HashEntry<K,V> first = tab[index];
373 <                
371 >                int index = hash & (tab.length - 1);
372 >                HashEntry<K,V> first = (HashEntry<K,V>)tab[index];
373 >
374                  HashEntry<K,V> e = first;
375 <                while (true) {
375 >                for (;;) {
376                      if (e == null)
377                          return null;
378 <                    if (e.hash == hash && eq(key, e.key))
378 >                    if (e.hash == hash && key.equals(e.key))
379                          break;
380                      e = e.next;
381                  }
# Line 403 | Line 383 | public class ConcurrentHashMap<K, V> ext
383                  V oldValue = e.value;
384                  if (value != null && !value.equals(oldValue))
385                      return null;
386 <                
386 >
387                  // All entries following removed node can stay in list, but
388 <                // all preceeding ones need to be cloned.  
388 >                // all preceeding ones need to be cloned.
389                  HashEntry<K,V> newFirst = e.next;
390 <                for (HashEntry<K,V> p = first; p != e; p = p.next)
391 <                    newFirst = new HashEntry<K,V>(p.hash, p.key,
390 >                for (HashEntry<K,V> p = first; p != e; p = p.next)
391 >                    newFirst = new HashEntry<K,V>(p.hash, p.key,
392                                                    p.value, newFirst);
393                  tab[index] = newFirst;
394 <                
395 <                count--; // write-volatile
416 <                return e.value;
394 >                count = c-1; // write-volatile
395 >                return oldValue;
396              }
397              finally {
398                  unlock();
# Line 423 | Line 402 | public class ConcurrentHashMap<K, V> ext
402          void clear() {
403              lock();
404              try {
405 <                HashEntry<K,V> tab[] = table;
406 <                for (int i = 0; i < tab.length ; i++)
405 >                HashEntry[] tab = table;
406 >                for (int i = 0; i < tab.length ; i++)
407                      tab[i] = null;
408                  count = 0; // write-volatile
409              }
# Line 455 | Line 434 | public class ConcurrentHashMap<K, V> ext
434          }
435  
436          public V getValue() {
437 <            return value;
437 >            return value;
438          }
439  
440          public V setValue(V newValue) {
# Line 471 | Line 450 | public class ConcurrentHashMap<K, V> ext
450          public boolean equals(Object o) {
451              if (!(o instanceof Entry))
452                  return false;
453 <            Entry<K,V> e = (Entry)o;
453 >            Entry<K,V> e = (Entry<K,V>)o;
454              return (key.equals(e.getKey()) && value.equals(e.getValue()));
455          }
456 <    
456 >
457          public int hashCode() {
458              return  key.hashCode() ^ value.hashCode();
459          }
# Line 484 | Line 463 | public class ConcurrentHashMap<K, V> ext
463          }
464      }
465  
466 <    
466 >
467      /* ---------------- Public operations -------------- */
468  
469      /**
# Line 500 | Line 479 | public class ConcurrentHashMap<K, V> ext
479       * negative or the load factor or number of segments are
480       * nonpositive.
481       */
482 <    public ConcurrentHashMap(int initialCapacity,
482 >    public ConcurrentHashMap(int initialCapacity,
483                               float loadFactor, int segments) {
484          if (!(loadFactor > 0) || initialCapacity < 0 || segments <= 0)
485              throw new IllegalArgumentException();
# Line 512 | Line 491 | public class ConcurrentHashMap<K, V> ext
491              ++sshift;
492              ssize <<= 1;
493          }
494 <        segmentShift = sshift;
494 >        segmentShift = 32 - sshift;
495          segmentMask = ssize - 1;
496 <        this.segments = new Segment<K,V>[ssize];
496 >        this.segments = new Segment[ssize];
497  
498          if (initialCapacity > MAXIMUM_CAPACITY)
499              initialCapacity = MAXIMUM_CAPACITY;
500          int c = initialCapacity / ssize;
501 <        if (c * ssize < initialCapacity)
501 >        if (c * ssize < initialCapacity)
502              ++c;
503          int cap = 1;
504          while (cap < c)
# Line 544 | Line 523 | public class ConcurrentHashMap<K, V> ext
523  
524      /**
525       * Constructs a new, empty map with a default initial capacity,
526 <     * load factor, and number of segments
526 >     * load factor, and number of segments.
527       */
528      public ConcurrentHashMap() {
529          this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
# Line 589 | Line 568 | public class ConcurrentHashMap<K, V> ext
568       *               <code>null</code>.
569       * @see     #put(Object, Object)
570       */
571 <    public V get(K key) {
571 >    public V get(Object key) {
572          int hash = hash(key); // throws NullPointerException if key null
573 <        return segmentFor(hash).get(key, segmentHashFor(hash));
573 >        return segmentFor(hash).get((K) key, hash);
574      }
575  
576      /**
577       * Tests if the specified object is a key in this table.
578 <     *
578 >     *
579       * @param   key   possible key.
580 <     * @return  <code>true</code> if and only if the specified object
581 <     *          is a key in this table, as determined by the
580 >     * @return  <code>true</code> if and only if the specified object
581 >     *          is a key in this table, as determined by the
582       *          <tt>equals</tt> method; <code>false</code> otherwise.
583       * @throws  NullPointerException  if the key is
584       *               <code>null</code>.
# Line 607 | Line 586 | public class ConcurrentHashMap<K, V> ext
586       */
587      public boolean containsKey(Object key) {
588          int hash = hash(key); // throws NullPointerException if key null
589 <        return segmentFor(hash).containsKey(key, segmentHashFor(hash));
589 >        return segmentFor(hash).containsKey(key, hash);
590      }
591  
592      /**
# Line 618 | Line 597 | public class ConcurrentHashMap<K, V> ext
597       *
598       * @param value value whose presence in this map is to be tested.
599       * @return <tt>true</tt> if this map maps one or more keys to the
600 <     * specified value.  
600 >     * specified value.
601       * @throws  NullPointerException  if the value is <code>null</code>.
602       */
603      public boolean containsValue(Object value) {
604 <        if (value == null)
604 >        if (value == null)
605              throw new NullPointerException();
606  
607          for (int i = 0; i < segments.length; ++i) {
# Line 638 | Line 617 | public class ConcurrentHashMap<K, V> ext
617       *
618       * Note that this method is identical in functionality to containsValue,
619       * (which is part of the Map interface in the collections framework).
620 <     *
620 >     *
621       * @param      value   a value to search for.
622       * @return     <code>true</code> if and only if some key maps to the
623 <     *             <code>value</code> argument in this table as
623 >     *             <code>value</code> argument in this table as
624       *             determined by the <tt>equals</tt> method;
625       *             <code>false</code> otherwise.
626       * @throws  NullPointerException  if the value is <code>null</code>.
# Line 654 | Line 633 | public class ConcurrentHashMap<K, V> ext
633      }
634  
635      /**
636 <     * Maps the specified <code>key</code> to the specified
637 <     * <code>value</code> in this table. Neither the key nor the
636 >     * Maps the specified <code>key</code> to the specified
637 >     * <code>value</code> in this table. Neither the key nor the
638       * value can be <code>null</code>. <p>
639       *
640 <     * The value can be retrieved by calling the <code>get</code> method
641 <     * with a key that is equal to the original key.
640 >     * The value can be retrieved by calling the <code>get</code> method
641 >     * with a key that is equal to the original key.
642       *
643       * @param      key     the table key.
644       * @param      value   the value.
# Line 670 | Line 649 | public class ConcurrentHashMap<K, V> ext
649       * @see     Object#equals(Object)
650       * @see     #get(Object)
651       */
652 <    public V put(K key, V value) {
653 <        if (value == null)
652 >    public V put(K key, V value) {
653 >        if (value == null)
654              throw new NullPointerException();
655 <        int hash = hash(key);
656 <        return segmentFor(hash).put(key, segmentHashFor(hash), value, false);
655 >        int hash = hash(key);
656 >        return segmentFor(hash).put(key, hash, value, false);
657      }
658  
659      /**
# Line 699 | Line 678 | public class ConcurrentHashMap<K, V> ext
678       *            <tt>null</tt>.
679       *
680       **/
681 <    public V putIfAbsent(K key, V value) {
682 <        if (value == null)
681 >    public V putIfAbsent(K key, V value) {
682 >        if (value == null)
683              throw new NullPointerException();
684 <        int hash = hash(key);
685 <        return segmentFor(hash).put(key, segmentHashFor(hash), value, true);
684 >        int hash = hash(key);
685 >        return segmentFor(hash).put(key, hash, value, true);
686      }
687  
688  
# Line 715 | Line 694 | public class ConcurrentHashMap<K, V> ext
694       *
695       * @param t Mappings to be stored in this map.
696       */
697 <    public <K1 extends K, V1 extends V> void putAll(Map<K1,V1> t) {
698 <        Iterator<Map.Entry<K1,V1>> it = t.entrySet().iterator();
697 >    public void putAll(Map<? extends K, ? extends V> t) {
698 >        Iterator<Map.Entry<? extends K, ? extends V>> it = t.entrySet().iterator();
699          while (it.hasNext()) {
700 <            Entry<K,V> e = (Entry) it.next();
700 >            Entry<? extends K, ? extends V> e = it.next();
701              put(e.getKey(), e.getValue());
702          }
703      }
704  
705      /**
706 <     * Removes the key (and its corresponding value) from this
706 >     * Removes the key (and its corresponding value) from this
707       * table. This method does nothing if the key is not in the table.
708       *
709       * @param   key   the key that needs to be removed.
# Line 735 | Line 714 | public class ConcurrentHashMap<K, V> ext
714       */
715      public V remove(Object key) {
716          int hash = hash(key);
717 <        return segmentFor(hash).remove(key, segmentHashFor(hash), null);
717 >        return segmentFor(hash).remove(key, hash, null);
718      }
719  
720      /**
721       * Removes the (key, value) pair from this
722       * table. This method does nothing if the key is not in the table,
723 <     * or if the key is associated with a different value.
723 >     * or if the key is associated with a different value.
724       *
725       * @param   key   the key that needs to be removed.
726       * @param   value   the associated value. If the value is null,
# Line 751 | Line 730 | public class ConcurrentHashMap<K, V> ext
730       * @throws  NullPointerException  if the key is
731       *               <code>null</code>.
732       */
733 <    public V remove(Object key, Object value) {
733 >    public boolean remove(Object key, Object value) {
734          int hash = hash(key);
735 <        return segmentFor(hash).remove(key, segmentHashFor(hash), value);
735 >        return segmentFor(hash).remove(key, hash, value) != null;
736      }
737  
738      /**
739       * Removes all mappings from this map.
740       */
741      public void clear() {
742 <        for (int i = 0; i < segments.length; ++i)
742 >        for (int i = 0; i < segments.length; ++i)
743              segments[i].clear();
744      }
745  
# Line 780 | Line 759 | public class ConcurrentHashMap<K, V> ext
759          int segs = segments.length;
760          int cap = (int)(size() / lf);
761          if (cap < segs) cap = segs;
762 <        ConcurrentHashMap t = new ConcurrentHashMap(cap, lf, segs);
762 >        ConcurrentHashMap<K,V> t = new ConcurrentHashMap<K,V>(cap, lf, segs);
763          t.putAll(this);
764          return t;
765      }
# Line 793 | Line 772 | public class ConcurrentHashMap<K, V> ext
772       * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
773       * <tt>clear</tt> operations.  It does not support the <tt>add</tt> or
774       * <tt>addAll</tt> operations.
775 +     * The returned <tt>iterator</tt> is a "weakly consistent" iterator that
776 +     * will never throw {@link java.util.ConcurrentModificationException},
777 +     * and guarantees to traverse elements as they existed upon
778 +     * construction of the iterator, and may (but is not guaranteed to)
779 +     * reflect any modifications subsequent to construction.
780       *
781       * @return a set view of the keys contained in this map.
782       */
# Line 810 | Line 794 | public class ConcurrentHashMap<K, V> ext
794       * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
795       * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
796       * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
797 +     * The returned <tt>iterator</tt> is a "weakly consistent" iterator that
798 +     * will never throw {@link java.util.ConcurrentModificationException},
799 +     * and guarantees to traverse elements as they existed upon
800 +     * construction of the iterator, and may (but is not guaranteed to)
801 +     * reflect any modifications subsequent to construction.
802       *
803       * @return a collection view of the values contained in this map.
804       */
# Line 828 | Line 817 | public class ConcurrentHashMap<K, V> ext
817       * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
818       * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
819       * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
820 +     * The returned <tt>iterator</tt> is a "weakly consistent" iterator that
821 +     * will never throw {@link java.util.ConcurrentModificationException},
822 +     * and guarantees to traverse elements as they existed upon
823 +     * construction of the iterator, and may (but is not guaranteed to)
824 +     * reflect any modifications subsequent to construction.
825       *
826       * @return a collection view of the mappings contained in this map.
827       */
# Line 866 | Line 860 | public class ConcurrentHashMap<K, V> ext
860      }
861  
862      /* ---------------- Iterator Support -------------- */
863 <    
863 >
864      private abstract class HashIterator {
865          private int nextSegmentIndex;
866          private int nextTableIndex;
867 <        private HashEntry<K, V>[] currentTable;
867 >        private HashEntry[] currentTable;
868          private HashEntry<K, V> nextEntry;
869          private HashEntry<K, V> lastReturned;
870  
# Line 885 | Line 879 | public class ConcurrentHashMap<K, V> ext
879          private void advance() {
880              if (nextEntry != null && (nextEntry = nextEntry.next) != null)
881                  return;
882 <                
882 >
883              while (nextTableIndex >= 0) {
884 <                if ( (nextEntry = currentTable[nextTableIndex--]) != null)
884 >                if ( (nextEntry = (HashEntry<K,V>)currentTable[nextTableIndex--]) != null)
885                      return;
886              }
887 <                
887 >
888              while (nextSegmentIndex >= 0) {
889 <                Segment<K,V> seg = segments[nextSegmentIndex--];
889 >                Segment<K,V> seg = (Segment<K,V>)segments[nextSegmentIndex--];
890                  if (seg.count != 0) {
891                      currentTable = seg.table;
892                      for (int j = currentTable.length - 1; j >= 0; --j) {
893 <                        if ( (nextEntry = currentTable[j]) != null) {
893 >                        if ( (nextEntry = (HashEntry<K,V>)currentTable[j]) != null) {
894                              nextTableIndex = j - 1;
895                              return;
896                          }
# Line 970 | Line 964 | public class ConcurrentHashMap<K, V> ext
964          }
965      }
966  
967 <    private class EntrySet extends AbstractSet {
967 >    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
968          public Iterator<Map.Entry<K,V>> iterator() {
969              return new EntryIterator();
970          }
# Line 985 | Line 979 | public class ConcurrentHashMap<K, V> ext
979              if (!(o instanceof Map.Entry))
980                  return false;
981              Map.Entry<K,V> e = (Map.Entry<K,V>)o;
982 <            return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()) != null;
982 >            return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
983          }
984          public int size() {
985              return ConcurrentHashMap.this.size();
# Line 1011 | Line 1005 | public class ConcurrentHashMap<K, V> ext
1005          s.defaultWriteObject();
1006  
1007          for (int k = 0; k < segments.length; ++k) {
1008 <            Segment<K,V> seg = segments[k];
1008 >            Segment<K,V> seg = (Segment<K,V>)segments[k];
1009              seg.lock();
1010              try {
1011 <                HashEntry<K,V>[] tab = seg.table;
1011 >                HashEntry[] tab = seg.table;
1012                  for (int i = 0; i < tab.length; ++i) {
1013 <                    for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
1013 >                    for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i]; e != null; e = e.next) {
1014                          s.writeObject(e.key);
1015                          s.writeObject(e.value);
1016                      }
# Line 1042 | Line 1036 | public class ConcurrentHashMap<K, V> ext
1036  
1037          // Initialize each segment to be minimally sized, and let grow.
1038          for (int i = 0; i < segments.length; ++i) {
1039 <            segments[i].setTable(new HashEntry<K,V>[1]);
1039 >            segments[i].setTable(new HashEntry[1]);
1040          }
1041  
1042          // Read the keys and values, and put the mappings in the table
1043 <        while (true) {
1043 >        for (;;) {
1044              K key = (K) s.readObject();
1045              V value = (V) s.readObject();
1046              if (key == null)
# Line 1055 | Line 1049 | public class ConcurrentHashMap<K, V> ext
1049          }
1050      }
1051   }
1052 <        
1052 >

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines