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.24 by dl, Fri Oct 10 23:51:28 2003 UTC vs.
Revision 1.72 by dl, Sat May 28 13:31:22 2005 UTC

# Line 1 | Line 1
1   /*
2   * Written by Doug Lea with assistance from members of JCP JSR-166
3 < * Expert Group and released to the public domain. Use, modify, and
4 < * redistribute this code in any way without acknowledgement.
3 > * Expert Group and released to the public domain, as explained at
4 > * http://creativecommons.org/licenses/publicdomain
5   */
6  
7   package java.util.concurrent;
# Line 17 | Line 17 | import java.io.ObjectOutputStream;
17   * adjustable expected concurrency for updates. This class obeys the
18   * same functional specification as {@link java.util.Hashtable}, and
19   * includes versions of methods corresponding to each method of
20 < * <tt>Hashtable</tt> . However, even though all operations are
20 > * <tt>Hashtable</tt>. However, even though all operations are
21   * thread-safe, retrieval operations do <em>not</em> entail locking,
22   * and there is <em>not</em> any support for locking the entire table
23   * in a way that prevents all access.  This class is fully
24   * interoperable with <tt>Hashtable</tt> in programs that rely on its
25   * thread safety but not on its synchronization details.
26   *
27 < * <p> Retrieval operations (including <tt>get</tt>) ordinarily
28 < * overlap with update operations (including <tt>put</tt> and
29 < * <tt>remove</tt>). Retrievals reflect the results of the most
30 < * recently <em>completed</em> update operations holding upon their
31 < * onset.  For aggregate operations such as <tt>putAll</tt> and
32 < * <tt>clear</tt>, concurrent retrievals may reflect insertion or
27 > * <p> Retrieval operations (including <tt>get</tt>) generally do not
28 > * block, so may overlap with update operations (including
29 > * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results
30 > * of the most recently <em>completed</em> update operations holding
31 > * upon their onset.  For aggregate operations such as <tt>putAll</tt>
32 > * and <tt>clear</tt>, concurrent retrievals may reflect insertion or
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 <tt>ConcurrentModificationException</tt>.
37 < * However, Iterators are designed to be used by only one thread at a
38 < * 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
45   * vary.  Ideally, you should choose a value to accommodate as many
46 < * threads as will ever concurrently access the table. Using a
46 > * threads as will ever concurrently modify the table. Using a
47   * significantly higher value than you need can waste space and time,
48   * and a significantly lower value can lead to thread contention. But
49   * overestimates and underestimates within an order of magnitude do
50 < * not usually have much noticeable impact.
50 > * not usually have much noticeable impact. A value of one is
51 > * appropriate when it is known that only one thread will modify and
52 > * all others will only read. Also, resizing this or any other kind of
53 > * hash table is a relatively slow operation, so, when possible, it is
54 > * a good idea to provide estimates of expected table sizes in
55 > * constructors.
56   *
57 < * <p>This class implements all of the <em>optional</em> methods
58 < * of the {@link Map} and {@link Iterator} interfaces.
57 > * <p>This class and its views and iterators implement all of the
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
63 < * 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">
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
72   */
73   public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
74 <        implements ConcurrentMap<K, V>, Cloneable, Serializable {
74 >        implements ConcurrentMap<K, V>, Serializable {
75      private static final long serialVersionUID = 7249069246763182397L;
76  
77      /*
# Line 72 | 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 final int DEFAULT_INITIAL_CAPACITY = 16;
89 >
90 >    /**
91 >     * The default load factor for this table, used when not
92 >     * otherwise specified in a constructor.
93 >     */
94 >    static final float DEFAULT_LOAD_FACTOR = 0.75f;
95 >
96 >    /**
97 >     * The default concurrency level for this table, used when not
98 >     * otherwise specified in a constructor.
99       */
100 <    private static int DEFAULT_INITIAL_CAPACITY = 16;
100 >    static final int DEFAULT_CONCURRENCY_LEVEL = 16;
101  
102      /**
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 indexible
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;
108 >    static final int MAXIMUM_CAPACITY = 1 << 30;
109  
110      /**
111 <     * The default load factor for this table.  Used when not
112 <     * otherwise specified in constructor.
111 >     * The maximum number of segments to allow; used to bound
112 >     * constructor arguments.
113       */
114 <    static final float DEFAULT_LOAD_FACTOR = 0.75f;
93 <
94 <    /**
95 <     * The default number of concurrency control segments.
96 <     **/
97 <    private static final int DEFAULT_SEGMENTS = 16;
114 >    static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
115  
116      /**
117 <     * The maximum number of segments to allow; used to bound ctor arguments.
117 >     * Number of unsynchronized retries in size and containsValue
118 >     * methods before resorting to locking. This is used to avoid
119 >     * unbounded retries if tables undergo continuous modification
120 >     * which would make it impossible to obtain an accurate result.
121       */
122 <    private static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
122 >    static final int RETRIES_BEFORE_LOCK = 2;
123  
124      /* ---------------- Fields -------------- */
125  
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 <     **/
130 <    private final int segmentMask;
129 >     */
130 >    final int segmentMask;
131  
132      /**
133       * Shift value for indexing within segments.
134 <     **/
135 <    private final int segmentShift;
134 >     */
135 >    final int segmentShift;
136  
137      /**
138       * The segments, each of which is a specialized hash table
139       */
140 <    private final Segment[] segments;
140 >    final Segment<K,V>[] segments;
141  
142 <    private transient Set<K> keySet;
143 <    private transient Set<Map.Entry<K,V>> entrySet;
144 <    private transient Collection<V> values;
142 >    transient Set<K> keySet;
143 >    transient Set<Map.Entry<K,V>> entrySet;
144 >    transient Collection<V> values;
145  
146      /* ---------------- Small Utilities -------------- */
147  
148      /**
149 <     * Return a hash code for non-null Object x.
150 <     * Uses the same hash code spreader as most other j.u hash tables.
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 <    private static int hash(Object x) {
154 >    static int hash(Object x) {
155          int h = x.hashCode();
156          h += ~(h << 9);
157          h ^=  (h >>> 14);
# Line 141 | Line 161 | public class ConcurrentHashMap<K, V> ext
161      }
162  
163      /**
164 <     * Return the segment that should be used for key with given hash
164 >     * Returns the segment that should be used for key with given hash
165 >     * @param hash the hash code for the key
166 >     * @return the segment
167       */
168 <    private Segment<K,V> segmentFor(int hash) {
169 <        return (Segment<K,V>) segments[(hash >>> segmentShift) & segmentMask];
168 >    final Segment<K,V> segmentFor(int hash) {
169 >        return segments[(hash >>> segmentShift) & segmentMask];
170      }
171  
172      /* ---------------- Inner Classes -------------- */
173  
174      /**
175 +     * ConcurrentHashMap list entry. Note that this is never exported
176 +     * out as a user-visible Map.Entry.
177 +     *
178 +     * Because the value field is volatile, not final, it is legal wrt
179 +     * the Java Memory Model for an unsynchronized reader to see null
180 +     * instead of initial value when read via a data race.  Although a
181 +     * reordering leading to this is not likely to ever actually
182 +     * occur, the Segment.readValueUnderLock method is used as a
183 +     * backup in case a null (pre-initialized) value is ever seen in
184 +     * an unsynchronized access method.
185 +     */
186 +    static final class HashEntry<K,V> {
187 +        final K key;
188 +        final int hash;
189 +        volatile V value;
190 +        final HashEntry<K,V> next;
191 +
192 +        HashEntry(K key, int hash, HashEntry<K,V> next, V value) {
193 +            this.key = key;
194 +            this.hash = hash;
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 +    /**
206       * Segments are specialized versions of hash tables.  This
207       * subclasses from ReentrantLock opportunistically, just to
208       * simplify some locking and avoid separate construction.
209 <     **/
210 <    private static final class Segment<K,V> extends ReentrantLock implements Serializable {
209 >     */
210 >    static final class Segment<K,V> extends ReentrantLock implements Serializable {
211          /*
212           * Segments maintain a table of entry lists that are ALWAYS
213           * kept in a consistent state, so can be read without locking.
# Line 167 | Line 220 | public class ConcurrentHashMap<K, V> ext
220           * is less than two for the default load factor threshold.)
221           *
222           * Read operations can thus proceed without locking, but rely
223 <         * on a memory barrier to ensure that completed write
224 <         * operations performed by other threads are
225 <         * noticed. Conveniently, the "count" field, tracking the
226 <         * number of elements, can also serve as the volatile variable
227 <         * providing proper read/write barriers. This is convenient
228 <         * because this field needs to be read in many read operations
176 <         * anyway.
223 >         * on selected uses of volatiles to ensure that completed
224 >         * write operations performed by other threads are
225 >         * noticed. For most purposes, the "count" field, tracking the
226 >         * number of elements, serves as that volatile variable
227 >         * ensuring visibility.  This is convenient because this field
228 >         * needs to be read in many read operations anyway:
229           *
230 <         * Implementors note. The basic rules for all this are:
179 <         *
180 <         *   - All unsynchronized read operations must first read the
230 >         *   - All (unsynchronized) read operations must first read the
231           *     "count" field, and should not look at table entries if
232           *     it is 0.
233           *
234 <         *   - All synchronized write operations should write to
235 <         *     the "count" field after updating. The operations must not
236 <         *     take any action that could even momentarily cause
237 <         *     a concurrent read operation to see inconsistent
238 <         *     data. This is made easier by the nature of the read
239 <         *     operations in Map. For example, no operation
234 >         *   - All (synchronized) write operations should write to
235 >         *     the "count" field after structurally changing any bin.
236 >         *     The operations must not take any action that could even
237 >         *     momentarily cause a concurrent read operation to see
238 >         *     inconsistent data. This is made easier by the nature of
239 >         *     the read operations in Map. For example, no operation
240           *     can reveal that the table has grown but the threshold
241           *     has not yet been updated, so there are no atomicity
242           *     requirements for this with respect to reads.
243           *
244 <         * As a guide, all critical volatile reads and writes are marked
245 <         * in code comments.
244 >         * As a guide, all critical volatile reads and writes to the
245 >         * count field are marked in code comments.
246           */
247  
248          private static final long serialVersionUID = 2249069246763182397L;
249  
250          /**
251           * The number of elements in this segment's region.
252 <         **/
252 >         */
253          transient volatile int count;
254  
255          /**
256 <         * Number of updates; used for checking lack of modifications
257 <         * in bulk-read methods.
256 >         * Number of updates that alter the size of the table. This is
257 >         * used during bulk-read methods to make sure they see a
258 >         * consistent snapshot: If modCounts change during a traversal
259 >         * of segments computing size or checking containsValue, then
260 >         * we might have an inconsistent view of state so (usually)
261 >         * must retry.
262           */
263          transient int modCount;
264  
265          /**
266           * The table is rehashed when its size exceeds this threshold.
267 <         * (The value of this field is always (int)(capacity *
268 <         * loadFactor).)
267 >         * (The value of this field is always <tt>(int)(capacity *
268 >         * loadFactor)</tt>.)
269           */
270 <        private transient int threshold;
270 >        transient int threshold;
271  
272          /**
273 <         * The per-segment table
274 <         */
221 <        transient HashEntry[] table;
273 >         * The per-segment table. */
274 >        transient volatile HashEntry<K,V>[] table;
275  
276          /**
277           * The load factor for the hash table.  Even though this value
# Line 226 | Line 279 | public class ConcurrentHashMap<K, V> ext
279           * links to outer object.
280           * @serial
281           */
282 <        private final float loadFactor;
282 >        final float loadFactor;
283  
284          Segment(int initialCapacity, float lf) {
285              loadFactor = lf;
286 <            setTable(new HashEntry[initialCapacity]);
286 >            setTable(HashEntry.<K,V>newArray(initialCapacity));
287 >        }
288 >
289 >        @SuppressWarnings("unchecked")
290 >        static final <K,V> Segment<K,V>[] newArray(int i) {
291 >            return new Segment[i];
292          }
293  
294          /**
295 <         * Set table to new HashEntry array.
295 >         * Sets table to new HashEntry array.
296           * Call only while holding lock or in constructor.
297 <         **/
298 <        private void setTable(HashEntry[] newTable) {
241 <            table = newTable;
297 >         */
298 >        void setTable(HashEntry<K,V>[] newTable) {
299              threshold = (int)(newTable.length * loadFactor);
300 <            count = count; // write-volatile
300 >            table = newTable;
301 >        }
302 >
303 >        /**
304 >         * Returns properly casted first entry of bin for given hash.
305 >         */
306 >        HashEntry<K,V> getFirst(int hash) {
307 >            HashEntry<K,V>[] tab = table;
308 >            return tab[hash & (tab.length - 1)];
309 >        }
310 >
311 >        /**
312 >         * Reads value field of an entry under lock. Called if value
313 >         * field ever appears to be null. This is possible only if a
314 >         * compiler happens to reorder a HashEntry initialization with
315 >         * its table assignment, which is legal under memory model
316 >         * but is not known to ever occur.
317 >         */
318 >        V readValueUnderLock(HashEntry<K,V> e) {
319 >            lock();
320 >            try {
321 >                return e.value;
322 >            } finally {
323 >                unlock();
324 >            }
325          }
326  
327          /* Specialized implementations of map methods */
328  
329 <        V get(K key, int hash) {
329 >        V get(Object key, int hash) {
330              if (count != 0) { // read-volatile
331 <                HashEntry[] tab = table;
251 <                int index = hash & (tab.length - 1);
252 <                HashEntry<K,V> e = (HashEntry<K,V>) tab[index];
331 >                HashEntry<K,V> e = getFirst(hash);
332                  while (e != null) {
333 <                    if (e.hash == hash && key.equals(e.key))
334 <                        return e.value;
333 >                    if (e.hash == hash && key.equals(e.key)) {
334 >                        V v = e.value;
335 >                        if (v != null)
336 >                            return v;
337 >                        return readValueUnderLock(e); // recheck
338 >                    }
339                      e = e.next;
340                  }
341              }
# Line 261 | Line 344 | public class ConcurrentHashMap<K, V> ext
344  
345          boolean containsKey(Object key, int hash) {
346              if (count != 0) { // read-volatile
347 <                HashEntry[] tab = table;
265 <                int index = hash & (tab.length - 1);
266 <                HashEntry<K,V> e = (HashEntry<K,V>) tab[index];
347 >                HashEntry<K,V> e = getFirst(hash);
348                  while (e != null) {
349                      if (e.hash == hash && key.equals(e.key))
350                          return true;
# Line 275 | Line 356 | public class ConcurrentHashMap<K, V> ext
356  
357          boolean containsValue(Object value) {
358              if (count != 0) { // read-volatile
359 <                HashEntry[] tab = table;
359 >                HashEntry<K,V>[] tab = table;
360                  int len = tab.length;
361 <                for (int i = 0 ; i < len; i++)
362 <                    for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i] ; e != null ; e = e.next)
363 <                        if (value.equals(e.value))
361 >                for (int i = 0 ; i < len; i++) {
362 >                    for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
363 >                        V v = e.value;
364 >                        if (v == null) // recheck
365 >                            v = readValueUnderLock(e);
366 >                        if (value.equals(v))
367                              return true;
368 +                    }
369 +                }
370              }
371              return false;
372          }
373  
374 +        boolean replace(K key, int hash, V oldValue, V newValue) {
375 +            lock();
376 +            try {
377 +                HashEntry<K,V> e = getFirst(hash);
378 +                while (e != null && (e.hash != hash || !key.equals(e.key)))
379 +                    e = e.next;
380 +
381 +                boolean replaced = false;
382 +                if (e != null && oldValue.equals(e.value)) {
383 +                    replaced = true;
384 +                    e.value = newValue;
385 +                }
386 +                return replaced;
387 +            } finally {
388 +                unlock();
389 +            }
390 +        }
391 +
392 +        V replace(K key, int hash, V newValue) {
393 +            lock();
394 +            try {
395 +                HashEntry<K,V> e = getFirst(hash);
396 +                while (e != null && (e.hash != hash || !key.equals(e.key)))
397 +                    e = e.next;
398 +
399 +                V oldValue = null;
400 +                if (e != null) {
401 +                    oldValue = e.value;
402 +                    e.value = newValue;
403 +                }
404 +                return oldValue;
405 +            } finally {
406 +                unlock();
407 +            }
408 +        }
409 +
410 +
411          V put(K key, int hash, V value, boolean onlyIfAbsent) {
412              lock();
413              try {
414                  int c = count;
415 <                HashEntry[] tab = table;
415 >                if (c++ > threshold) // ensure capacity
416 >                    rehash();
417 >                HashEntry<K,V>[] tab = table;
418                  int index = hash & (tab.length - 1);
419 <                HashEntry<K,V> first = (HashEntry<K,V>) tab[index];
419 >                HashEntry<K,V> first = tab[index];
420 >                HashEntry<K,V> e = first;
421 >                while (e != null && (e.hash != hash || !key.equals(e.key)))
422 >                    e = e.next;
423  
424 <                for (HashEntry<K,V> e = first; e != null; e = (HashEntry<K,V>) e.next) {
425 <                    if (e.hash == hash && key.equals(e.key)) {
426 <                        V oldValue = e.value;
427 <                        if (!onlyIfAbsent)
428 <                            e.value = value;
301 <                        ++modCount;
302 <                        count = c; // write-volatile
303 <                        return oldValue;
304 <                    }
424 >                V oldValue;
425 >                if (e != null) {
426 >                    oldValue = e.value;
427 >                    if (!onlyIfAbsent)
428 >                        e.value = value;
429                  }
430 <
431 <                tab[index] = new HashEntry<K,V>(hash, key, value, first);
432 <                ++modCount;
433 <                ++c;
434 <                count = c; // write-volatile
435 <                if (c > threshold)
436 <                    setTable(rehash(tab));
313 <                return null;
430 >                else {
431 >                    oldValue = null;
432 >                    ++modCount;
433 >                    tab[index] = new HashEntry<K,V>(key, hash, first, value);
434 >                    count = c; // write-volatile
435 >                }
436 >                return oldValue;
437              } finally {
438                  unlock();
439              }
440          }
441  
442 <        private HashEntry[] rehash(HashEntry[] oldTable) {
442 >        void rehash() {
443 >            HashEntry<K,V>[] oldTable = table;
444              int oldCapacity = oldTable.length;
445              if (oldCapacity >= MAXIMUM_CAPACITY)
446 <                return oldTable;
446 >                return;
447  
448              /*
449               * Reclassify nodes in each list to new Map.  Because we are
# Line 328 | Line 452 | public class ConcurrentHashMap<K, V> ext
452               * offset. We eliminate unnecessary node creation by catching
453               * cases where old nodes can be reused because their next
454               * fields won't change. Statistically, at the default
455 <             * threshhold, only about one-sixth of them need cloning when
455 >             * threshold, only about one-sixth of them need cloning when
456               * a table doubles. The nodes they replace will be garbage
457               * collectable as soon as they are no longer referenced by any
458               * reader thread that may be in the midst of traversing table
459               * right now.
460               */
461  
462 <            HashEntry[] newTable = new HashEntry[oldCapacity << 1];
462 >            HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1);
463 >            threshold = (int)(newTable.length * loadFactor);
464              int sizeMask = newTable.length - 1;
465              for (int i = 0; i < oldCapacity ; i++) {
466                  // We need to guarantee that any existing reads of old Map can
467                  //  proceed. So we cannot yet null out each bin.
468 <                HashEntry<K,V> e = (HashEntry<K,V>)oldTable[i];
468 >                HashEntry<K,V> e = oldTable[i];
469  
470                  if (e != null) {
471                      HashEntry<K,V> next = e.next;
# Line 368 | Line 493 | public class ConcurrentHashMap<K, V> ext
493                          // Clone all remaining nodes
494                          for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
495                              int k = p.hash & sizeMask;
496 <                            newTable[k] = new HashEntry<K,V>(p.hash,
497 <                                                             p.key,
498 <                                                             p.value,
374 <                                                             (HashEntry<K,V>) newTable[k]);
496 >                            HashEntry<K,V> n = newTable[k];
497 >                            newTable[k] = new HashEntry<K,V>(p.key, p.hash,
498 >                                                             n, p.value);
499                          }
500                      }
501                  }
502              }
503 <            return newTable;
503 >            table = newTable;
504          }
505  
506          /**
# Line 385 | Line 509 | public class ConcurrentHashMap<K, V> ext
509          V remove(Object key, int hash, Object value) {
510              lock();
511              try {
512 <                int c = count;
513 <                HashEntry[] tab = table;
512 >                int c = count - 1;
513 >                HashEntry<K,V>[] tab = table;
514                  int index = hash & (tab.length - 1);
515 <                HashEntry<K,V> first = (HashEntry<K,V>)tab[index];
392 <
515 >                HashEntry<K,V> first = tab[index];
516                  HashEntry<K,V> e = first;
517 <                for (;;) {
395 <                    if (e == null)
396 <                        return null;
397 <                    if (e.hash == hash && key.equals(e.key))
398 <                        break;
517 >                while (e != null && (e.hash != hash || !key.equals(e.key)))
518                      e = e.next;
400                }
519  
520 <                V oldValue = e.value;
521 <                if (value != null && !value.equals(oldValue))
522 <                    return null;
523 <
524 <                // All entries following removed node can stay in list, but
525 <                // all preceeding ones need to be cloned.
526 <                HashEntry<K,V> newFirst = e.next;
527 <                for (HashEntry<K,V> p = first; p != e; p = p.next)
528 <                    newFirst = new HashEntry<K,V>(p.hash, p.key,
529 <                                                  p.value, newFirst);
530 <                tab[index] = newFirst;
531 <                ++modCount;
532 <                count = c-1; // write-volatile
520 >                V oldValue = null;
521 >                if (e != null) {
522 >                    V v = e.value;
523 >                    if (value == null || value.equals(v)) {
524 >                        oldValue = v;
525 >                        // All entries following removed node can stay
526 >                        // in list, but all preceding ones need to be
527 >                        // cloned.
528 >                        ++modCount;
529 >                        HashEntry<K,V> newFirst = e.next;
530 >                        for (HashEntry<K,V> p = first; p != e; p = p.next)
531 >                            newFirst = new HashEntry<K,V>(p.key, p.hash,
532 >                                                          newFirst, p.value);
533 >                        tab[index] = newFirst;
534 >                        count = c; // write-volatile
535 >                    }
536 >                }
537                  return oldValue;
538              } finally {
539                  unlock();
# Line 419 | Line 541 | public class ConcurrentHashMap<K, V> ext
541          }
542  
543          void clear() {
544 <            lock();
545 <            try {
546 <                HashEntry[] tab = table;
547 <                for (int i = 0; i < tab.length ; i++)
548 <                    tab[i] = null;
549 <                ++modCount;
550 <                count = 0; // write-volatile
551 <            } finally {
552 <                unlock();
544 >            if (count != 0) {
545 >                lock();
546 >                try {
547 >                    HashEntry<K,V>[] tab = table;
548 >                    for (int i = 0; i < tab.length ; i++)
549 >                        tab[i] = null;
550 >                    ++modCount;
551 >                    count = 0; // write-volatile
552 >                } finally {
553 >                    unlock();
554 >                }
555              }
556          }
557      }
558  
435    /**
436     * ConcurrentHashMap list entry.
437     */
438    private static class HashEntry<K,V> implements Entry<K,V> {
439        private final K key;
440        private V value;
441        private final int hash;
442        private final HashEntry<K,V> next;
443
444        HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
445            this.value = value;
446            this.hash = hash;
447            this.key = key;
448            this.next = next;
449        }
450
451        public K getKey() {
452            return key;
453        }
454
455        public V getValue() {
456            return value;
457        }
458
459        public V setValue(V newValue) {
460            // We aren't required to, and don't provide any
461            // visibility barriers for setting value.
462            if (newValue == null)
463                throw new NullPointerException();
464            V oldValue = this.value;
465            this.value = newValue;
466            return oldValue;
467        }
468
469        public boolean equals(Object o) {
470            if (!(o instanceof Entry))
471                return false;
472            Entry<K,V> e = (Entry<K,V>)o;
473            return (key.equals(e.getKey()) && value.equals(e.getValue()));
474        }
475
476        public int hashCode() {
477            return  key.hashCode() ^ value.hashCode();
478        }
479
480        public String toString() {
481            return key + "=" + value;
482        }
483    }
559  
560  
561      /* ---------------- Public operations -------------- */
562  
563      /**
564 <     * Constructs a new, empty map with the specified initial
565 <     * capacity and the specified load factor.
564 >     * Creates a new, empty map with the specified initial
565 >     * capacity, load factor and concurrency level.
566       *
567       * @param initialCapacity the initial capacity. The implementation
568       * performs internal sizing to accommodate this many elements.
569       * @param loadFactor  the load factor threshold, used to control resizing.
570 +     * Resizing may be performed when the average number of elements per
571 +     * bin exceeds this threshold.
572       * @param concurrencyLevel the estimated number of concurrently
573       * updating threads. The implementation performs internal sizing
574 <     * to try to accommodate this many threads.  
574 >     * to try to accommodate this many threads.
575       * @throws IllegalArgumentException if the initial capacity is
576       * negative or the load factor or concurrencyLevel are
577       * nonpositive.
# Line 516 | Line 593 | public class ConcurrentHashMap<K, V> ext
593          }
594          segmentShift = 32 - sshift;
595          segmentMask = ssize - 1;
596 <        this.segments = new Segment[ssize];
596 >        this.segments = Segment.newArray(ssize);
597  
598          if (initialCapacity > MAXIMUM_CAPACITY)
599              initialCapacity = MAXIMUM_CAPACITY;
# Line 532 | Line 609 | public class ConcurrentHashMap<K, V> ext
609      }
610  
611      /**
612 <     * Constructs a new, empty map with the specified initial
613 <     * capacity,  and with default load factor and concurrencyLevel.
612 >     * Creates a new, empty map with the specified initial capacity
613 >     * and load factor and with the default concurrencyLevel
614 >     * (<tt>16</tt>).
615       *
616       * @param initialCapacity The implementation performs internal
617       * sizing to accommodate this many elements.
618 +     * @param loadFactor  the load factor threshold, used to control resizing.
619 +     * Resizing may be performed when the average number of elements per
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 +    public ConcurrentHashMap(int initialCapacity, float loadFactor) {
625 +        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
626 +    }
627 +
628 +    /**
629 +     * Creates a new, empty map with the specified initial capacity,
630 +     * and with default load factor (<tt>0.75f</tt>)
631 +     * and concurrencyLevel (<tt>16</tt>).
632 +     *
633 +     * @param initialCapacity the initial capacity. The implementation
634 +     * performs internal sizing to accommodate this many elements.
635       * @throws IllegalArgumentException if the initial capacity of
636       * elements is negative.
637       */
638      public ConcurrentHashMap(int initialCapacity) {
639 <        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
639 >        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
640      }
641  
642      /**
643 <     * Constructs a new, empty map with a default initial capacity,
644 <     * load factor, and concurrencyLevel.
643 >     * Creates a new, empty map with a default initial capacity
644 >     * (<tt>16</tt>), load factor
645 >     * (<tt>0.75f</tt>), and concurrencyLevel
646 >     * (<tt>16</tt>).
647       */
648      public ConcurrentHashMap() {
649 <        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
649 >        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
650      }
651  
652      /**
653 <     * Constructs a new map with the same mappings as the given map.  The
654 <     * map is created with a capacity of twice the number of mappings in
655 <     * the given map or 11 (whichever is greater), and a default load factor.
653 >     * Creates a new map with the same mappings as the given map.  The
654 >     * map is created with a capacity of 1.5 times the number of
655 >     * mappings in the given map or <tt>16</tt>
656 >     * (whichever is greater), and a default load factor
657 >     * (<tt>0.75f</tt>) and concurrencyLevel
658 >     * (<tt>16</tt>).
659 >     * @param m the map
660       */
661 <    public <A extends K, B extends V> ConcurrentHashMap(Map<A,B> t) {
662 <        this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1,
663 <                      11),
664 <             DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
665 <        putAll(t);
661 >    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
662 >        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
663 >                      DEFAULT_INITIAL_CAPACITY),
664 >             DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
665 >        putAll(m);
666      }
667  
668 <    // inherit Map javadoc
668 >    /**
669 >     * Returns <tt>true</tt> if this map contains no key-value mappings.
670 >     *
671 >     * @return <tt>true</tt> if this map contains no key-value mappings
672 >     */
673      public boolean isEmpty() {
674 +        final Segment<K,V>[] segments = this.segments;
675          /*
676 <         * We need to keep track of per-segment modCounts to avoid ABA
676 >         * We keep track of per-segment modCounts to avoid ABA
677           * problems in which an element in one segment was added and
678           * in another removed during traversal, in which case the
679           * table was never actually empty at any point. Note the
# Line 580 | Line 686 | public class ConcurrentHashMap<K, V> ext
686          for (int i = 0; i < segments.length; ++i) {
687              if (segments[i].count != 0)
688                  return false;
689 <            else
689 >            else
690                  mcsum += mc[i] = segments[i].modCount;
691          }
692          // If mcsum happens to be zero, then we know we got a snapshot
# Line 589 | Line 695 | public class ConcurrentHashMap<K, V> ext
695          if (mcsum != 0) {
696              for (int i = 0; i < segments.length; ++i) {
697                  if (segments[i].count != 0 ||
698 <                    mc[i] != segments[i].modCount)
698 >                    mc[i] != segments[i].modCount)
699                      return false;
700              }
701          }
702          return true;
703      }
704  
705 <    // inherit Map javadoc
705 >    /**
706 >     * Returns the number of key-value mappings in this map.  If the
707 >     * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
708 >     * <tt>Integer.MAX_VALUE</tt>.
709 >     *
710 >     * @return the number of key-value mappings in this map
711 >     */
712      public int size() {
713 +        final Segment<K,V>[] segments = this.segments;
714 +        long sum = 0;
715 +        long check = 0;
716          int[] mc = new int[segments.length];
717 <        for (;;) {
718 <            long sum = 0;
717 >        // Try a few times to get accurate count. On failure due to
718 >        // continuous async changes in table, resort to locking.
719 >        for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
720 >            check = 0;
721 >            sum = 0;
722              int mcsum = 0;
723              for (int i = 0; i < segments.length; ++i) {
724                  sum += segments[i].count;
725                  mcsum += mc[i] = segments[i].modCount;
726              }
609            int check = 0;
727              if (mcsum != 0) {
728                  for (int i = 0; i < segments.length; ++i) {
729                      check += segments[i].count;
# Line 616 | Line 733 | public class ConcurrentHashMap<K, V> ext
733                      }
734                  }
735              }
736 <            if (check == sum) {
737 <                if (sum > Integer.MAX_VALUE)
738 <                    return Integer.MAX_VALUE;
739 <                else
740 <                    return (int)sum;
741 <            }
736 >            if (check == sum)
737 >                break;
738 >        }
739 >        if (check != sum) { // Resort to locking all segments
740 >            sum = 0;
741 >            for (int i = 0; i < segments.length; ++i)
742 >                segments[i].lock();
743 >            for (int i = 0; i < segments.length; ++i)
744 >                sum += segments[i].count;
745 >            for (int i = 0; i < segments.length; ++i)
746 >                segments[i].unlock();
747          }
748 +        if (sum > Integer.MAX_VALUE)
749 +            return Integer.MAX_VALUE;
750 +        else
751 +            return (int)sum;
752      }
753  
628
754      /**
755 <     * Returns the value to which the specified key is mapped in this table.
755 >     * Returns the value to which this map maps the specified key, or
756 >     * <tt>null</tt> if the map contains no mapping for the key.
757       *
758 <     * @param   key   a key in the table.
759 <     * @return  the value to which the key is mapped in this table;
760 <     *          <tt>null</tt> if the key is not mapped to any value in
761 <     *          this table.
636 <     * @throws  NullPointerException  if the key is
637 <     *               <tt>null</tt>.
758 >     * @param key key whose associated value is to be returned
759 >     * @return the value associated with <tt>key</tt> in this map, or
760 >     *         <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
765 <        return segmentFor(hash).get((K) key, hash);
765 >        return segmentFor(hash).get(key, hash);
766      }
767  
768      /**
769       * Tests if the specified object is a key in this table.
770       *
771 <     * @param   key   possible key.
772 <     * @return  <tt>true</tt> if and only if the specified object
773 <     *          is a key in this table, as determined by the
774 <     *          <tt>equals</tt> method; <tt>false</tt> otherwise.
775 <     * @throws  NullPointerException  if the key is
652 <     *               <tt>null</tt>.
771 >     * @param  key   possible key
772 >     * @return <tt>true</tt> if and only if the specified object
773 >     *         is a key in this table, as determined by the
774 >     *         <tt>equals</tt> method; <tt>false</tt> otherwise.
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
# Line 662 | Line 785 | public class ConcurrentHashMap<K, V> ext
785       * traversal of the hash table, and so is much slower than
786       * method <tt>containsKey</tt>.
787       *
788 <     * @param value value whose presence in this map is to be tested.
788 >     * @param value value whose presence in this map is to be tested
789       * @return <tt>true</tt> if this map maps one or more keys to the
790 <     * specified value.
791 <     * @throws  NullPointerException  if the value is <tt>null</tt>.
790 >     *         specified value
791 >     * @throws NullPointerException if the specified value is null
792       */
793      public boolean containsValue(Object value) {
794          if (value == null)
795              throw new NullPointerException();
796  
797 +        // See explanation of modCount use above
798 +
799 +        final Segment<K,V>[] segments = this.segments;
800          int[] mc = new int[segments.length];
801 <        for (;;) {
801 >
802 >        // Try a few times without locking
803 >        for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
804              int sum = 0;
805              int mcsum = 0;
806              for (int i = 0; i < segments.length; ++i) {
# Line 694 | Line 822 | public class ConcurrentHashMap<K, V> ext
822              if (cleanSweep)
823                  return false;
824          }
825 +        // Resort to locking all segments
826 +        for (int i = 0; i < segments.length; ++i)
827 +            segments[i].lock();
828 +        boolean found = false;
829 +        try {
830 +            for (int i = 0; i < segments.length; ++i) {
831 +                if (segments[i].containsValue(value)) {
832 +                    found = true;
833 +                    break;
834 +                }
835 +            }
836 +        } finally {
837 +            for (int i = 0; i < segments.length; ++i)
838 +                segments[i].unlock();
839 +        }
840 +        return found;
841      }
842  
843      /**
844       * Legacy method testing if some key maps into the specified value
845       * in this table.  This method is identical in functionality to
846 <     * {@link #containsValue}, and  exists solely to ensure
846 >     * {@link #containsValue}, and exists solely to ensure
847       * full compatibility with class {@link java.util.Hashtable},
848       * which supported this method prior to introduction of the
849       * Java Collections framework.
850  
851 <     * @param      value   a value to search for.
852 <     * @return     <tt>true</tt> if and only if some key maps to the
853 <     *             <tt>value</tt> argument in this table as
854 <     *             determined by the <tt>equals</tt> method;
855 <     *             <tt>false</tt> otherwise.
856 <     * @throws  NullPointerException  if the value is <tt>null</tt>.
851 >     * @param  value a value to search for
852 >     * @return <tt>true</tt> if and only if some key maps to the
853 >     *         <tt>value</tt> argument in this table as
854 >     *         determined by the <tt>equals</tt> method;
855 >     *         <tt>false</tt> otherwise
856 >     * @throws NullPointerException if the specified value is null
857       */
858      public boolean contains(Object value) {
859          return containsValue(value);
# Line 718 | Line 862 | public class ConcurrentHashMap<K, V> ext
862      /**
863       * Maps the specified <tt>key</tt> to the specified
864       * <tt>value</tt> in this table. Neither the key nor the
865 <     * value can be <tt>null</tt>. <p>
865 >     * value can be <tt>null</tt>.
866       *
867 <     * The value can be retrieved by calling the <tt>get</tt> method
867 >     * <p> The value can be retrieved by calling the <tt>get</tt> method
868       * with a key that is equal to the original key.
869       *
870 <     * @param      key     the table key.
871 <     * @param      value   the value.
872 <     * @return     the previous value of the specified key in this table,
873 <     *             or <tt>null</tt> if it did not have one.
874 <     * @throws  NullPointerException  if the key or value is
731 <     *               <tt>null</tt>.
870 >     * @param key key with which the specified value is to be associated
871 >     * @param value value to be associated with the specified key
872 >     * @return the previous value associated with <tt>key</tt>, or
873 >     *         <tt>null</tt> if there was no mapping for <tt>key</tt>
874 >     * @throws NullPointerException if the specified key or value is null
875       */
876      public V put(K key, V value) {
877          if (value == null)
# Line 738 | Line 881 | public class ConcurrentHashMap<K, V> ext
881      }
882  
883      /**
884 <     * If the specified key is not already associated
742 <     * with a value, associate it with the given value.
743 <     * This is equivalent to
744 <     * <pre>
745 <     *   if (!map.containsKey(key))
746 <     *      return map.put(key, value);
747 <     *   else
748 <     *      return map.get(key);
749 <     * </pre>
750 <     * Except that the action is performed atomically.
751 <     * @param key key with which the specified value is to be associated.
752 <     * @param value value to be associated with the specified key.
753 <     * @return previous value associated with specified key, or <tt>null</tt>
754 <     *         if there was no mapping for key.  A <tt>null</tt> return can
755 <     *         also indicate that the map previously associated <tt>null</tt>
756 <     *         with the specified key, if the implementation supports
757 <     *         <tt>null</tt> values.
758 <     *
759 <     * @throws UnsupportedOperationException if the <tt>put</tt> operation is
760 <     *            not supported by this map.
761 <     * @throws ClassCastException if the class of the specified key or value
762 <     *            prevents it from being stored in this map.
763 <     * @throws NullPointerException if the specified key or value is
764 <     *            <tt>null</tt>.
884 >     * {@inheritDoc}
885       *
886 <     **/
886 >     * @return the previous value associated with the specified key,
887 >     *         or <tt>null</tt> if there was no mapping for the key
888 >     * @throws NullPointerException if the specified key or value is null
889 >     */
890      public V putIfAbsent(K key, V value) {
891          if (value == null)
892              throw new NullPointerException();
# Line 771 | Line 894 | public class ConcurrentHashMap<K, V> ext
894          return segmentFor(hash).put(key, hash, value, true);
895      }
896  
774
897      /**
898       * Copies all of the mappings from the specified map to this one.
777     *
899       * These mappings replace any mappings that this map had for any of the
900 <     * keys currently in the specified Map.
900 >     * keys currently in the specified map.
901       *
902 <     * @param t Mappings to be stored in this map.
902 >     * @param m mappings to be stored in this map
903       */
904 <    public void putAll(Map<? extends K, ? extends V> t) {
905 <        for (Iterator<Map.Entry<? extends K, ? extends V>> it = (Iterator<Map.Entry<? extends K, ? extends V>>) t.entrySet().iterator(); it.hasNext(); ) {
904 >    public void putAll(Map<? extends K, ? extends V> m) {
905 >        for (Iterator<? extends Map.Entry<? extends K, ? extends V>> it = (Iterator<? extends Map.Entry<? extends K, ? extends V>>) m.entrySet().iterator(); it.hasNext(); ) {
906              Entry<? extends K, ? extends V> e = it.next();
907              put(e.getKey(), e.getValue());
908          }
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
798 <     *               <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);
# Line 803 | Line 923 | public class ConcurrentHashMap<K, V> ext
923      }
924  
925      /**
926 <     * Remove entry for key only if currently mapped to given value.
927 <     * Acts as
928 <     * <pre>
809 <     *  if (map.get(key).equals(value)) {
810 <     *     map.remove(key);
811 <     *     return true;
812 <     * } else return false;
813 <     * </pre>
814 <     * except that the action is performed atomically.
815 <     * @param key key with which the specified value is associated.
816 <     * @param value value associated with the specified key.
817 <     * @return true if the value was removed
818 <     * @throws NullPointerException if the specified key is
819 <     *            <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 +        if (value == null)
932 +            return false;
933          int hash = hash(key);
934          return segmentFor(hash).remove(key, hash, value) != null;
935      }
936  
937      /**
938 <     * Removes all mappings from this map.
938 >     * {@inheritDoc}
939 >     *
940 >     * @throws NullPointerException if any of the arguments are null
941       */
942 <    public void clear() {
943 <        for (int i = 0; i < segments.length; ++i)
944 <            segments[i].clear();
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);
946 >        return segmentFor(hash).replace(key, hash, oldValue, newValue);
947      }
948  
949 +    /**
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);
960 +        return segmentFor(hash).replace(key, hash, value);
961 +    }
962  
963      /**
964 <     * Returns a shallow copy of this
965 <     * <tt>ConcurrentHashMap</tt> instance: the keys and
966 <     * values themselves are not cloned.
967 <     *
968 <     * @return a shallow copy of this map.
841 <     */
842 <    public Object clone() {
843 <        // We cannot call super.clone, since it would share final
844 <        // segments array, and there's no way to reassign finals.
845 <
846 <        float lf = segments[0].loadFactor;
847 <        int segs = segments.length;
848 <        int cap = (int)(size() / lf);
849 <        if (cap < segs) cap = segs;
850 <        ConcurrentHashMap<K,V> t = new ConcurrentHashMap<K,V>(cap, lf, segs);
851 <        t.putAll(this);
852 <        return t;
964 >     * Removes all of the mappings from this map.
965 >     */
966 >    public void clear() {
967 >        for (int i = 0; i < segments.length; ++i)
968 >            segments[i].clear();
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 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.
868     *
869     * @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  
876
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 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.
890     *
891     * @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  
898
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 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.
913     *
914     * @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  
921
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 931 | Line 1043 | public class ConcurrentHashMap<K, V> ext
1043  
1044      /**
1045       * Returns an enumeration of the values in this table.
934     * Use the Enumeration methods on the returned object to fetch the elements
935     * sequentially.
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 943 | Line 1053 | public class ConcurrentHashMap<K, V> ext
1053  
1054      /* ---------------- Iterator Support -------------- */
1055  
1056 <    private abstract class HashIterator {
1057 <        private int nextSegmentIndex;
1058 <        private int nextTableIndex;
1059 <        private HashEntry[] currentTable;
1060 <        private HashEntry<K, V> nextEntry;
1061 <        private HashEntry<K, V> lastReturned;
1056 >    abstract class HashIterator {
1057 >        int nextSegmentIndex;
1058 >        int nextTableIndex;
1059 >        HashEntry<K,V>[] currentTable;
1060 >        HashEntry<K, V> nextEntry;
1061 >        HashEntry<K, V> lastReturned;
1062  
1063 <        private HashIterator() {
1063 >        HashIterator() {
1064              nextSegmentIndex = segments.length - 1;
1065              nextTableIndex = -1;
1066              advance();
# Line 958 | Line 1068 | public class ConcurrentHashMap<K, V> ext
1068  
1069          public boolean hasMoreElements() { return hasNext(); }
1070  
1071 <        private void advance() {
1071 >        final void advance() {
1072              if (nextEntry != null && (nextEntry = nextEntry.next) != null)
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 999 | Line 1109 | public class ConcurrentHashMap<K, V> ext
1109          }
1110      }
1111  
1112 <    private class KeyIterator extends HashIterator implements Iterator<K>, Enumeration<K> {
1112 >    final class KeyIterator extends HashIterator implements Iterator<K>, Enumeration<K> {
1113          public K next() { return super.nextEntry().key; }
1114          public K nextElement() { return super.nextEntry().key; }
1115      }
1116  
1117 <    private class ValueIterator extends HashIterator implements Iterator<V>, Enumeration<V> {
1117 >    final class ValueIterator extends HashIterator implements Iterator<V>, Enumeration<V> {
1118          public V next() { return super.nextEntry().value; }
1119          public V nextElement() { return super.nextEntry().value; }
1120      }
1121  
1122 <    private class EntryIterator extends HashIterator implements Iterator<Entry<K,V>> {
1123 <        public Map.Entry<K,V> next() { return super.nextEntry(); }
1122 >
1123 >
1124 >    /**
1125 >     * Entry iterator. Exported Entry objects must write-through
1126 >     * changes in setValue, even if the nodes have been cloned. So we
1127 >     * cannot return internal HashEntry objects. Instead, the iterator
1128 >     * itself acts as a forwarding pseudo-entry.
1129 >     */
1130 >    final class EntryIterator extends HashIterator implements Map.Entry<K,V>, Iterator<Entry<K,V>> {
1131 >        public Map.Entry<K,V> next() {
1132 >            nextEntry();
1133 >            return this;
1134 >        }
1135 >
1136 >        public K getKey() {
1137 >            if (lastReturned == null)
1138 >                throw new IllegalStateException("Entry was removed");
1139 >            return lastReturned.key;
1140 >        }
1141 >
1142 >        public V getValue() {
1143 >            if (lastReturned == null)
1144 >                throw new IllegalStateException("Entry was removed");
1145 >            return ConcurrentHashMap.this.get(lastReturned.key);
1146 >        }
1147 >
1148 >        public V setValue(V value) {
1149 >            if (lastReturned == null)
1150 >                throw new IllegalStateException("Entry was removed");
1151 >            return ConcurrentHashMap.this.put(lastReturned.key, value);
1152 >        }
1153 >
1154 >        public boolean equals(Object o) {
1155 >            // If not acting as entry, just use default.
1156 >            if (lastReturned == null)
1157 >                return super.equals(o);
1158 >            if (!(o instanceof Map.Entry))
1159 >                return false;
1160 >            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1161 >            return eq(getKey(), e.getKey()) && eq(getValue(), e.getValue());
1162 >        }
1163 >
1164 >        public int hashCode() {
1165 >            // If not acting as entry, just use default.
1166 >            if (lastReturned == null)
1167 >                return super.hashCode();
1168 >
1169 >            Object k = getKey();
1170 >            Object v = getValue();
1171 >            return ((k == null) ? 0 : k.hashCode()) ^
1172 >                   ((v == null) ? 0 : v.hashCode());
1173 >        }
1174 >
1175 >        public String toString() {
1176 >            // If not acting as entry, just use default.
1177 >            if (lastReturned == null)
1178 >                return super.toString();
1179 >            else
1180 >                return getKey() + "=" + getValue();
1181 >        }
1182 >
1183 >        boolean eq(Object o1, Object o2) {
1184 >            return (o1 == null ? o2 == null : o1.equals(o2));
1185 >        }
1186 >
1187      }
1188  
1189 <    private class KeySet extends AbstractSet<K> {
1189 >    final class KeySet extends AbstractSet<K> {
1190          public Iterator<K> iterator() {
1191              return new KeyIterator();
1192          }
# Line 1029 | Line 1202 | public class ConcurrentHashMap<K, V> ext
1202          public void clear() {
1203              ConcurrentHashMap.this.clear();
1204          }
1205 +        public Object[] toArray() {
1206 +            Collection<K> c = new ArrayList<K>();
1207 +            for (Iterator<K> i = iterator(); i.hasNext(); )
1208 +                c.add(i.next());
1209 +            return c.toArray();
1210 +        }
1211 +        public <T> T[] toArray(T[] a) {
1212 +            Collection<K> c = new ArrayList<K>();
1213 +            for (Iterator<K> i = iterator(); i.hasNext(); )
1214 +                c.add(i.next());
1215 +            return c.toArray(a);
1216 +        }
1217      }
1218  
1219 <    private class Values extends AbstractCollection<V> {
1219 >    final class Values extends AbstractCollection<V> {
1220          public Iterator<V> iterator() {
1221              return new ValueIterator();
1222          }
# Line 1044 | Line 1229 | public class ConcurrentHashMap<K, V> ext
1229          public void clear() {
1230              ConcurrentHashMap.this.clear();
1231          }
1232 +        public Object[] toArray() {
1233 +            Collection<V> c = new ArrayList<V>();
1234 +            for (Iterator<V> i = iterator(); i.hasNext(); )
1235 +                c.add(i.next());
1236 +            return c.toArray();
1237 +        }
1238 +        public <T> T[] toArray(T[] a) {
1239 +            Collection<V> c = new ArrayList<V>();
1240 +            for (Iterator<V> i = iterator(); i.hasNext(); )
1241 +                c.add(i.next());
1242 +            return c.toArray(a);
1243 +        }
1244      }
1245  
1246 <    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1246 >    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1247          public Iterator<Map.Entry<K,V>> iterator() {
1248              return new EntryIterator();
1249          }
1250          public boolean contains(Object o) {
1251              if (!(o instanceof Map.Entry))
1252                  return false;
1253 <            Map.Entry<K,V> e = (Map.Entry<K,V>)o;
1253 >            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1254              V v = ConcurrentHashMap.this.get(e.getKey());
1255              return v != null && v.equals(e.getValue());
1256          }
1257          public boolean remove(Object o) {
1258              if (!(o instanceof Map.Entry))
1259                  return false;
1260 <            Map.Entry<K,V> e = (Map.Entry<K,V>)o;
1260 >            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1261              return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
1262          }
1263          public int size() {
# Line 1069 | Line 1266 | public class ConcurrentHashMap<K, V> ext
1266          public void clear() {
1267              ConcurrentHashMap.this.clear();
1268          }
1269 +        public Object[] toArray() {
1270 +            // Since we don't ordinarily have distinct Entry objects, we
1271 +            // must pack elements using exportable SimpleEntry
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();
1276 +        }
1277 +        public <T> T[] toArray(T[] a) {
1278 +            Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size());
1279 +            for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); )
1280 +                c.add(new AbstractMap.SimpleEntry<K,V>(i.next()));
1281 +            return c.toArray(a);
1282 +        }
1283 +
1284      }
1285  
1286      /* ---------------- Serialization Support -------------- */
1287  
1288      /**
1289 <     * Save the state of the <tt>ConcurrentHashMap</tt>
1290 <     * instance to a stream (i.e.,
1079 <     * serialize it).
1289 >     * Save the state of the <tt>ConcurrentHashMap</tt> instance to a
1290 >     * stream (i.e., serialize it).
1291       * @param s the stream
1292       * @serialData
1293       * the key (Object) and value (Object)
# Line 1087 | Line 1298 | public class ConcurrentHashMap<K, V> ext
1298          s.defaultWriteObject();
1299  
1300          for (int k = 0; k < segments.length; ++k) {
1301 <            Segment<K,V> seg = (Segment<K,V>)segments[k];
1301 >            Segment<K,V> seg = segments[k];
1302              seg.lock();
1303              try {
1304 <                HashEntry[] tab = seg.table;
1304 >                HashEntry<K,V>[] tab = seg.table;
1305                  for (int i = 0; i < tab.length; ++i) {
1306 <                    for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i]; e != null; e = e.next) {
1306 >                    for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
1307                          s.writeObject(e.key);
1308                          s.writeObject(e.value);
1309                      }
# Line 1106 | Line 1317 | public class ConcurrentHashMap<K, V> ext
1317      }
1318  
1319      /**
1320 <     * Reconstitute the <tt>ConcurrentHashMap</tt>
1321 <     * instance from a stream (i.e.,
1111 <     * deserialize it).
1320 >     * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a
1321 >     * stream (i.e., deserialize it).
1322       * @param s the stream
1323       */
1324      private void readObject(java.io.ObjectInputStream s)
# Line 1117 | Line 1327 | public class ConcurrentHashMap<K, V> ext
1327  
1328          // Initialize each segment to be minimally sized, and let grow.
1329          for (int i = 0; i < segments.length; ++i) {
1330 <            segments[i].setTable(new HashEntry[1]);
1330 >            segments[i].setTable((HashEntry<K,V>[])HashEntry.newArray(1));
1331          }
1332  
1333          // Read the keys and values, and put the mappings in the table
# Line 1130 | Line 1340 | public class ConcurrentHashMap<K, V> ext
1340          }
1341      }
1342   }
1133

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines