Mega Code Archive

 
Categories / Java / Collections Data Structure
 

A version of Hashtable supporting concurrency for both retrievals and updates

/*  File: ConcurrentHashMap  Written by Doug Lea. Adapted and released, under explicit  permission, from JDK1.2 HashMap.java and Hashtable.java which  carries the following copyright:  * Copyright 1997 by Sun Microsystems, Inc.,  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.  * All rights reserved.  *  * This software is the confidential and proprietary information  * of Sun Microsystems, Inc. ("Confidential Information").  You  * shall not disclose such Confidential Information and shall use  * it only in accordance with the terms of the license agreement  * you entered into with Sun.  History:  Date       Who                What  26nov2000  dl               Created, based on ConcurrentReaderHashMap  12jan2001  dl               public release  17nov2001  dl               Minor tunings  24oct2003  dl               Segment implements Serializable  */ import java.io.IOException; import java.io.Serializable; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.Enumeration; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; /**  * A version of Hashtable supporting concurrency for both retrievals and  * updates:  *   * <dl>  * <dt> Retrievals  *   * <dd> Retrievals may overlap updates. (This is the same policy as  * ConcurrentReaderHashMap.) Successful retrievals using get(key) and  * containsKey(key) usually run without locking. Unsuccessful retrievals (i.e.,  * when the key is not present) do involve brief synchronization (locking).  * Because retrieval operations can ordinarily overlap with update operations  * (i.e., put, remove, and their derivatives), retrievals can only be guaranteed  * to return the results of the most recently <em>completed</em> operations  * holding upon their onset. Retrieval operations may or may not return results  * reflecting in-progress writing operations. However, the retrieval operations  * do always return consistent results -- either those holding before any single  * modification or after it, but never a nonsense result. For aggregate  * operations such as putAll and clear, concurrent reads may reflect insertion  * or removal of only some entries.  * <p>  *   * Iterators and Enumerations (i.e., those returned by keySet().iterator(),  * entrySet().iterator(), values().iterator(), keys(), and elements()) return  * elements reflecting the state of the hash table at some point at or since the  * creation of the iterator/enumeration. They will return at most one instance  * of each element (via next()/nextElement()), but might or might not reflect  * puts and removes that have been processed since they were created. They do  * <em>not</em> throw ConcurrentModificationException. However, these  * iterators are designed to be used by only one thread at a time. Passing an  * iterator across multiple threads may lead to unpredictable results if the  * table is being concurrently modified.  * <p>  *   *   * <dt> Updates  *   * <dd> This class supports a hard-wired preset <em>concurrency  * level</em> of  * 32. This allows a maximum of 32 put and/or remove operations to proceed  * concurrently. This level is an upper bound on concurrency, not a guarantee,  * since it interacts with how well-strewn elements are across bins of the  * table. (The preset value in part reflects the fact that even on large  * multiprocessors, factors other than synchronization tend to be bottlenecks  * when more than 32 threads concurrently attempt updates.) Additionally,  * operations triggering internal resizing and clearing do not execute  * concurrently with any operation.  * <p>  *   * There is <em>NOT</em> any support for locking the entire table to prevent  * updates. This makes it imposssible, for example, to add an element only if it  * is not already present, since another thread may be in the process of doing  * the same thing. If you need such capabilities, consider instead using the  * ConcurrentReaderHashMap class.  *   * </dl>  *   * Because of how concurrency control is split up, the size() and isEmpty()  * methods require accumulations across 32 control segments, and so might be  * slightly slower than you expect.  * <p>  *   * This class may be used as a direct replacement for java.util.Hashtable in any  * application that does not rely on the ability to lock the entire table to  * prevent updates. As of this writing, it performs much faster than Hashtable  * in typical multi-threaded applications with multiple readers and writers.  * Like Hashtable but unlike java.util.HashMap, this class does NOT allow  * <tt>null</tt> to be used as a key or value.  * <p>  *   * Implementation note: A slightly faster implementation of this class will be  * possible once planned Java Memory Model revisions are in place.  *   * <p>[<a  * href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html">  * Introduction to this package. </a>]  *   */ public class ConcurrentHashMap extends AbstractMap implements Map, Cloneable, Serializable {   private static final long serialVersionUID = 1L;   /*    * The basic strategy is an optimistic-style scheme based on the guarantee    * that the hash table and its lists are always kept in a consistent enough    * state to be read without locking:    *     * Read operations first proceed without locking, by traversing the    * apparently correct list of the apparently correct bin. If an entry is    * found, but not invalidated (value field null), it is returned. If not    * found, operations must recheck (after a memory barrier) to make sure they    * are using both the right list and the right table (which can change under    * resizes). If invalidated, reads must acquire main update lock to wait out    * the update, and then re-traverse.    *     * All list additions are at the front of each bin, making it easy to check    * changes, and also fast to traverse. Entry next pointers are never    * assigned. Remove() builds new nodes when necessary to preserve this.    *     * Remove() (also clear()) invalidates removed nodes to alert read    * operations that they must wait out the full modifications.    *     * Locking for puts, removes (and, when necessary gets, etc) is controlled    * by Segments, each covering a portion of the table. During operations    * requiring global exclusivity (mainly resize and clear), ALL of these    * locks are acquired at once. Note that these segments are NOT contiguous --    * they are based on the least 5 bits of hashcodes. This ensures that the    * same segment controls the same slots before and after resizing, which is    * necessary for supporting concurrent retrievals. This comes at the price    * of a mismatch of logical vs physical locality, but this seems not to be a    * performance problem in practice.    *     */   /**    * The hash table data.    */   protected transient Entry[] table;   /**    * The number of concurrency control segments. The value can be at most 32    * since ints are used as bitsets over segments. Emprically, it doesn't seem    * to pay to decrease it either, so the value should be at least 32. In    * other words, do not redefine this :-)    */   protected static final int CONCURRENCY_LEVEL = 32;   /**    * Mask value for indexing into segments    */   protected static final int SEGMENT_MASK = CONCURRENCY_LEVEL - 1;   /**    * Bookkeeping for each concurrency control segment. Each segment contains a    * local count of the number of elements in its region. However, the main    * use of a Segment is for its lock.    */   protected final static class Segment implements Serializable   {     private static final long serialVersionUID = 1L;          /**      * The number of elements in this segment's region. It is always updated      * within synchronized blocks.      */     protected int count;     /**      * Get the count under synch.      * @return count under sync      */     protected synchronized int getCount()     {       return count;     }     /**      * Force a synchronization      */     protected synchronized void synch()     {     }   }   /**    * The array of concurrency control segments.    */   protected final Segment[] segments = new Segment[CONCURRENCY_LEVEL];   /**    * The default initial number of table slots for this table (32). Used when    * not otherwise specified in constructor.    */   public static final int DEFAULT_INITIAL_CAPACITY = 32;   /**    * The minimum capacity, used if a lower value is implicitly specified by    * either of the constructors with arguments. MUST be a power of two.    */   private static final int MINIMUM_CAPACITY = 32;   /**    * The maximum capacity, used if a higher value is implicitly specified by    * either of the constructors with arguments. MUST be a power of two <= 1<<30.    */   private static final int MAXIMUM_CAPACITY = 1 << 30;   /**    * The default load factor for this table (0.75) Used when not otherwise    * specified in constructor.    */   public static final float DEFAULT_LOAD_FACTOR = 0.75f;   /**    * The load factor for the hash table.    *     * @serial    */   protected final float loadFactor;   /**    * Per-segment resize threshold.    *     * @serial    */   protected int threshold;   /**    * Number of segments voting for resize. The table is doubled when 1/4 of    * the segments reach threshold. Volatile but updated without synch since    * this is just a heuristic.    */   protected transient volatile int votesForResize;   /**    * Return the number of set bits in w. For a derivation of this algorithm,    * see "Algorithms and data structures with applications to graphics and    * geometry", by Jurg Nievergelt and Klaus Hinrichs, Prentice Hall, 1993.    * See also notes by Torsten Sillke at    * http://www.mathematik.uni-bielefeld.de/~sillke/PROBLEMS/bitcount    * @param w arg    * @return number of set bits    */   protected static int bitcount(int w)   {     w -= (0xaaaaaaaa & w) >>> 1;     w = (w & 0x33333333) + ((w >>> 2) & 0x33333333);     w = (w + (w >>> 4)) & 0x0f0f0f0f;     w += w >>> 8;     w += w >>> 16;     return w & 0xff;   }   /**    * Returns the appropriate capacity (power of two) for the specified initial    * capacity argument.    * @param initialCapacity the initial capacity    * @return appropriate capacity    */   private int p2capacity(int initialCapacity)   {     int cap = initialCapacity;     // Compute the appropriate capacity     int result;     if (cap > MAXIMUM_CAPACITY || cap < 0)     {       result = MAXIMUM_CAPACITY;     }     else     {       result = MINIMUM_CAPACITY;       while (result < cap)       {         result <<= 1;       }     }     return result;   }   /**    * Return hash code for Object x. Since we are using power-of-two tables, it    * is worth the effort to improve hashcode via the same multiplicative    * scheme as used in IdentityHashMap.    * @param x     * @return hash code    */   protected static int hash(Object x)   {     int h = x.hashCode();     // Multiply by 127 (quickly, via shifts), and mix in some high     // bits to help guard against bunching of codes that are     // consecutive or equally spaced.     return ((h << 7) - h + (h >>> 9) + (h >>> 17));   }   /**    * Check for equality of non-null references x and y.    * @param x ref    * @param y ref    * @return is equal    */   protected boolean eq(Object x, Object y)   {     return x == y || x.equals(y);   }   /**    * Create table array and set the per-segment threshold *     * @param capacity     * @return table array    */   protected Entry[] newTable(int capacity)   {     threshold = (int)(capacity * loadFactor / CONCURRENCY_LEVEL) + 1;     return new Entry[capacity];   }   /**    * Constructs a new, empty map with the specified initial capacity and the    * specified load factor.    *     * @param initialCapacity    *            the initial capacity. The actual initial capacity is rounded    *            to the nearest power of two.    * @param loadFactor    *            the load factor threshold, used to control resizing. This    *            value is used in an approximate way: When at least a quarter    *            of the segments of the table reach per-segment threshold, or    *            one of the segments itself exceeds overall threshold, the    *            table is doubled. This will on average cause resizing when the    *            table-wide load factor is slightly less than the threshold. If    *            you'd like to avoid resizing, you can set this to a    *            ridiculously large value.    * @throws IllegalArgumentException    *             if the load factor is nonpositive.    */   public ConcurrentHashMap(int initialCapacity, float loadFactor)   {     if (!(loadFactor > 0))     {       throw new IllegalArgumentException("Illegal Load factor: " + loadFactor);     }     this.loadFactor = loadFactor;     for (int i = 0; i < segments.length; ++i)     {       segments[i] = new Segment();     }     int cap = p2capacity(initialCapacity);     table = newTable(cap);   }   /**    * Constructs a new, empty map with the specified initial capacity and    * default load factor.    *     * @param initialCapacity    *            the initial capacity of the ConcurrentHashMap.    * @throws IllegalArgumentException    *             if the initial maximum number of elements is less than zero.    */   public ConcurrentHashMap(int initialCapacity)   {     this(initialCapacity, DEFAULT_LOAD_FACTOR);   }   /**    * Constructs a new, empty map with a default initial capacity and default    * load factor.    */   public ConcurrentHashMap()   {     this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);   }   /**    * Constructs a new map with the same mappings as the given map. The map is    * created with a capacity of twice the number of mappings in the given map    * or 32 (whichever is greater), and a default load factor.    * @param t map to copy    */   public ConcurrentHashMap(Map t)   {     this(Math.max((int)(t.size() / DEFAULT_LOAD_FACTOR) + 1, MINIMUM_CAPACITY),         DEFAULT_LOAD_FACTOR);     putAll(t);   }   /**    * Returns the number of key-value mappings in this map.    *     * @return the number of key-value mappings in this map.    */   public int size()   {     int c = 0;     for (int i = 0; i < segments.length; ++i)     {       c += segments[i].getCount();     }     return c;   }   /**    * Returns <tt>true</tt> if this map contains no key-value mappings.    *     * @return <tt>true</tt> if this map contains no key-value mappings.    */   public boolean isEmpty()   {     for (int i = 0; i < segments.length; ++i)     {       if (segments[i].getCount() != 0)       {         return false;       }     }     return true;   }   /**    * Returns the value to which the specified key is mapped in this table.    *     * @param key    *            a key in the table.    * @return the value to which the key is mapped in this table;    *         <code>null</code> if the key is not mapped to any value in this    *         table.    * @exception NullPointerException    *                if the key is <code>null</code>.    * @see #put(Object, Object)    */   public Object get(Object key)   {     int hash = hash(key); // throws null pointer exception if key null     // Try first without locking...     Entry[] tab = table;     int index = hash & (tab.length - 1);     Entry first = tab[index];     Entry e;     for (e = first; e != null; e = e.next)     {       if (e.hash == hash && eq(key, e.key))       {         Object value = e.value;         if (value != null)         {           return value;         }         else         {           break;         }       }     }     // Recheck under synch if key apparently not there or interference     Segment seg = segments[hash & SEGMENT_MASK];     synchronized (seg)     {       tab = table;       index = hash & (tab.length - 1);       Entry newFirst = tab[index];       if (e != null || first != newFirst)       {         for (e = newFirst; e != null; e = e.next)         {           if (e.hash == hash && eq(key, e.key))           {             return e.value;           }         }       }       return null;     }   }   /**    * Tests if the specified object is a key in this table.    *     * @param key    *            possible key.    * @return <code>true</code> if and only if the specified object is a key    *         in this table, as determined by the <tt>equals</tt> method;    *         <code>false</code> otherwise.    * @exception NullPointerException    *                if the key is <code>null</code>.    * @see #contains(Object)    */   public boolean containsKey(Object key)   {     return get(key) != null;   }   /**    * Maps the specified <code>key</code> to the specified <code>value</code>    * in this table. Neither the key nor the value can be <code>null</code>.    * (Note that this policy is the same as for java.util.Hashtable, but unlike    * java.util.HashMap, which does accept nulls as valid keys and values.)    * <p>    *     * The value can be retrieved by calling the <code>get</code> method with    * a key that is equal to the original key.    *     * @param key    *            the table key.    * @param value    *            the value.    * @return the previous value of the specified key in this table, or    *         <code>null</code> if it did not have one.    * @exception NullPointerException    *                if the key or value is <code>null</code>.    * @see Object#equals(Object)    * @see #get(Object)    */   public Object put(Object key, Object value)   {     if (value == null)     {       throw new IllegalArgumentException("Value must not be null");     }     int hash = hash(key);     Segment seg = segments[hash & SEGMENT_MASK];     int segcount;     Entry[] tab;     int votes;     synchronized (seg)     {       tab = table;       int index = hash & (tab.length - 1);       Entry first = tab[index];       for (Entry e = first; e != null; e = e.next)       {         if (e.hash == hash && eq(key, e.key))         {           Object oldValue = e.value;           e.value = value;           return oldValue;         }       }       // Add to front of list       Entry newEntry = new Entry(hash, key, value, first);       tab[index] = newEntry;       if ((segcount = ++seg.count) < threshold)       {         return null;       }       int bit = (1 << (hash & SEGMENT_MASK));       votes = votesForResize;       if ((votes & bit) == 0)       {         votes = votesForResize |= bit;       }     }     // Attempt resize if 1/4 segs vote,     // or if this seg itself reaches the overall threshold.     // (The latter check is just a safeguard to avoid pathological cases.)     if (bitcount(votes) >= CONCURRENCY_LEVEL / 4 || segcount > (threshold * CONCURRENCY_LEVEL))     {       resize(0, tab);     }     return null;   }   /**    * Gather all locks in order to call rehash, by recursing within synch    * blocks for each segment index.    *     * @param index    *            the current segment. initially call value must be 0    * @param assumedTab    *            the state of table on first call to resize. If this changes on    *            any call, the attempt is aborted because the table has already    *            been resized by another thread.    */   protected void resize(int index, Entry[] assumedTab)   {     Segment seg = segments[index];     synchronized (seg)     {       if (assumedTab == table)       {         int next = index + 1;         if (next < segments.length)         {           resize(next, assumedTab);         }         else         {           rehash();         }       }     }   }   /**    * Rehashes the contents of this map into a new table with a larger    * capacity.    */   protected void rehash()   {     votesForResize = 0; // reset     Entry[] oldTable = table;     int oldCapacity = oldTable.length;     if (oldCapacity >= MAXIMUM_CAPACITY)     {       threshold = Integer.MAX_VALUE; // avoid retriggering       return;     }     int newCapacity = oldCapacity << 1;     Entry[] newTable = newTable(newCapacity);     int mask = newCapacity - 1;     /*      * Reclassify nodes in each list to new Map. Because we are using      * power-of-two expansion, the elements from each bin must either stay      * at same index, or move to oldCapacity+index. We also eliminate      * unnecessary node creation by catching cases where old nodes can be      * reused because their next fields won't change. Statistically, at the      * default threshhold, only about one-sixth of them need cloning. (The      * nodes they replace will be garbage collectable as soon as they are no      * longer referenced by any reader thread that may be in the midst of      * traversing table right now.)      */     for (int i = 0; i < oldCapacity; i++)     {       // We need to guarantee that any existing reads of old Map can       // proceed. So we cannot yet null out each bin.       Entry e = oldTable[i];       if (e != null)       {         int idx = e.hash & mask;         Entry next = e.next;         // Single node on list         if (next == null)         {           newTable[idx] = e;         }         else         {           // Reuse trailing consecutive sequence of all same bit           Entry lastRun = e;           int lastIdx = idx;           for (Entry last = next; last != null; last = last.next)           {             int k = last.hash & mask;             if (k != lastIdx)             {               lastIdx = k;               lastRun = last;             }           }           newTable[lastIdx] = lastRun;           // Clone all remaining nodes           for (Entry p = e; p != lastRun; p = p.next)           {             int k = p.hash & mask;             newTable[k] = new Entry(p.hash, p.key, p.value, newTable[k]);           }         }       }     }     table = newTable;   }   /**    * Removes the key (and its corresponding value) from this table. This    * method does nothing if the key is not in the table.    *     * @param key    *            the key that needs to be removed.    * @return the value to which the key had been mapped in this table, or    *         <code>null</code> if the key did not have a mapping.    * @exception NullPointerException    *                if the key is <code>null</code>.    */   public Object remove(Object key)   {     return remove(key, null);   }   /**    * Removes the (key, value) pair from this table. This method does nothing    * if the key is not in the table, or if the key is associated with a    * different value. This method is needed by EntrySet.    *     * @param key    *            the key that needs to be removed.    * @param value    *            the associated value. If the value is null, it means "any    *            value".    * @return the value to which the key had been mapped in this table, or    *         <code>null</code> if the key did not have a mapping.    * @exception NullPointerException    *                if the key is <code>null</code>.    */   protected Object remove(Object key, Object value)   {     /*      * Find the entry, then 1. Set value field to null, to force get() to      * retry 2. Rebuild the list without this entry. All entries following      * removed node can stay in list, but all preceeding ones need to be      * cloned. Traversals rely on this strategy to ensure that elements will      * not be repeated during iteration.      */     int hash = hash(key);     Segment seg = segments[hash & SEGMENT_MASK];     synchronized (seg)     {       Entry[] tab = table;       int index = hash & (tab.length - 1);       Entry first = tab[index];       Entry e = first;       for (;;)       {         if (e == null)         {           return null;         }         if (e.hash == hash && eq(key, e.key))         {           break;         }         e = e.next;       }       Object oldValue = e.value;       if (value != null && !value.equals(oldValue))       {         return null;       }       e.value = null;       Entry head = e.next;       for (Entry p = first; p != e; p = p.next)       {         head = new Entry(p.hash, p.key, p.value, head);       }       tab[index] = head;       seg.count--;       return oldValue;     }   }   /**    * Returns <tt>true</tt> if this map maps one or more keys to the    * specified value. Note: This method requires a full internal traversal of    * the hash table, and so is much slower than method <tt>containsKey</tt>.    *     * @param value    *            value whose presence in this map is to be tested.    * @return <tt>true</tt> if this map maps one or more keys to the    *         specified value.    * @exception NullPointerException    *                if the value is <code>null</code>.    */   public boolean containsValue(Object value)   {     if (value == null)     {       throw new IllegalArgumentException("Value must not be null");     }     for (int s = 0; s < segments.length; ++s)     {       Segment seg = segments[s];       Entry[] tab;       synchronized (seg)       {         tab = table;       }       for (int i = s; i < tab.length; i += segments.length)       {         for (Entry e = tab[i]; e != null; e = e.next)         {           if (value.equals(e.value))           {             return true;           }         }       }     }     return false;   }   /**    * Tests if some key maps into the specified value in this table. This    * operation is more expensive than the <code>containsKey</code> method.    * <p>    *     * Note that this method is identical in functionality to containsValue,    * (which is part of the Map interface in the collections framework).    *     * @param value    *            a value to search for.    * @return <code>true</code> if and only if some key maps to the    *         <code>value</code> argument in this table as determined by the    *         <tt>equals</tt> method; <code>false</code> otherwise.    * @exception NullPointerException    *                if the value is <code>null</code>.    * @see #containsKey(Object)    * @see #containsValue(Object)    * @see Map    */   public boolean contains(Object value)   {     return containsValue(value);   }   /**    * Copies all of the mappings from the specified map to this one.    *     * These mappings replace any mappings that this map had for any of the keys    * currently in the specified Map.    *     * @param t    *            Mappings to be stored in this map.    */   public void putAll(Map t)   {     int n = t.size();     if (n == 0)     {       return;     }     // Expand enough to hold at least n elements without resizing.     // We can only resize table by factor of two at a time.     // It is faster to rehash with fewer elements, so do it now.     for (;;)     {       Entry[] tab;       int max;       synchronized (segments[0])       { // must synch on some segment. pick 0.         tab = table;         max = threshold * CONCURRENCY_LEVEL;       }       if (n < max)       {         break;       }       resize(0, tab);     }     for (Iterator it = t.entrySet().iterator(); it.hasNext();)     {       Map.Entry entry = (Map.Entry)it.next();       put(entry.getKey(), entry.getValue());     }   }   /**    * Removes all mappings from this map.    */   public void clear()   {     // We don't need all locks at once so long as locks     // are obtained in low to high order     for (int s = 0; s < segments.length; ++s)     {       Segment seg = segments[s];       synchronized (seg)       {         Entry[] tab = table;         for (int i = s; i < tab.length; i += segments.length)         {           for (Entry e = tab[i]; e != null; e = e.next)           {             e.value = null;           }           tab[i] = null;           seg.count = 0;         }       }     }   }   /**    * Returns a shallow copy of this <tt>ConcurrentHashMap</tt> instance: the    * keys and values themselves are not cloned.    *     * @return a shallow copy of this map.    */   public Object clone()   {     // We cannot call super.clone, since it would share final segments     // array,     // and there's no way to reassign finals.     return new ConcurrentHashMap(this);   }   // Views   protected transient Set keySet = null;   protected transient Set entrySet = null;   protected transient Collection values = null;   /**    * Returns a set view of the keys contained in this map. The set is backed    * by the map, so changes to the map are reflected in the set, and    * vice-versa. The set supports element removal, which removes the    * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,    * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and    * <tt>clear</tt> operations. It does not support the <tt>add</tt> or    * <tt>addAll</tt> operations.    *     * @return a set view of the keys contained in this map.    */   public Set keySet()   {     Set ks = keySet;     return (ks != null) ? ks : (keySet = new KeySet());   }   private class KeySet extends AbstractSet   {     /**      * @see java.util.Set#iterator()      */     public Iterator iterator()     {       return new KeyIterator();     }     /**      * @see java.util.Set#size()      */     public int size()     {       return ConcurrentHashMap.this.size();     }     /**      * @see java.util.Set#contains(java.lang.Object)      */     public boolean contains(Object o)     {       return ConcurrentHashMap.this.containsKey(o);     }     /**      * @see java.util.Set#remove(java.lang.Object)      */     public boolean remove(Object o)     {       return ConcurrentHashMap.this.remove(o) != null;     }     /**      * @see java.util.Set#clear()      */     public void clear()     {       ConcurrentHashMap.this.clear();     }   }   /**    * Returns a collection view of the values contained in this map. The    * collection is backed by the map, so changes to the map are reflected in    * the collection, and vice-versa. The collection supports element removal,    * which removes the corresponding mapping from this map, via the    * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,    * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>    * operations. It does not support the <tt>add</tt> or <tt>addAll</tt>    * operations.    *     * @return a collection view of the values contained in this map.    */   public Collection values()   {     Collection vs = values;     return (vs != null) ? vs : (values = new Values());   }   private class Values extends AbstractCollection   {     /**      * @see java.util.AbstractCollection#iterator()      */     public Iterator iterator()     {       return new ValueIterator();     }     /**      * @see java.util.AbstractCollection#size()      */     public int size()     {       return ConcurrentHashMap.this.size();     }     /**      * @see java.util.AbstractCollection#contains(java.lang.Object)      */     public boolean contains(Object o)     {       return ConcurrentHashMap.this.containsValue(o);     }     /**      * @see java.util.AbstractCollection#clear()      */     public void clear()     {       ConcurrentHashMap.this.clear();     }   }   /**    * Returns a collection view of the mappings contained in this map. Each    * element in the returned collection is a <tt>Map.Entry</tt>. The    * collection is backed by the map, so changes to the map are reflected in    * the collection, and vice-versa. The collection supports element removal,    * which removes the corresponding mapping from the map, via the    * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,    * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>    * operations. It does not support the <tt>add</tt> or <tt>addAll</tt>    * operations.    *     * @return a collection view of the mappings contained in this map.    */   public Set entrySet()   {     Set es = entrySet;     return (es != null) ? es : (entrySet = new EntrySet());   }   private class EntrySet extends AbstractSet   {     /**      * @see java.util.Set#iterator()      */     public Iterator iterator()     {       return new HashIterator();     }     /**      * @see java.util.Set#contains(java.lang.Object)      */     public boolean contains(Object o)     {       if (!(o instanceof Map.Entry))       {         return false;       }       Map.Entry entry = (Map.Entry)o;       Object v = ConcurrentHashMap.this.get(entry.getKey());       return v != null && v.equals(entry.getValue());     }     /**      * @see java.util.Set#remove(java.lang.Object)      */     public boolean remove(Object o)     {       if (!(o instanceof Map.Entry))       {         return false;       }       Map.Entry e = (Map.Entry)o;       return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()) != null;     }     /**      * @see java.util.Set#size()      */     public int size()     {       return ConcurrentHashMap.this.size();     }     /**      * @see java.util.Set#clear()      */     public void clear()     {       ConcurrentHashMap.this.clear();     }   }   /**    * Returns an enumeration of the keys in this table.    *     * @return an enumeration of the keys in this table.    * @see Enumeration    * @see #elements()    * @see #keySet()    * @see Map    */   public Enumeration keys()   {     return new KeyIterator();   }   /**    * Returns an enumeration of the values in this table. Use the Enumeration    * methods on the returned object to fetch the elements sequentially.    *     * @return an enumeration of the values in this table.    * @see java.util.Enumeration    * @see #keys()    * @see #values()    * @see Map    */   public Enumeration elements()   {     return new ValueIterator();   }   /**    * ConcurrentHashMap collision list entry.    */   protected static class Entry implements Map.Entry   {     /*      * The use of volatile for value field ensures that we can detect status      * changes without synchronization. The other fields are never changed,      * and are marked as final.      */     protected final Object key;     protected volatile Object value;     protected final int hash;     protected final Entry next;     Entry(int hash, Object key, Object value, Entry next)     {       this.value = value;       this.hash = hash;       this.key = key;       this.next = next;     }     // Map.Entry Ops     /**      * @see java.util.Map.Entry#getKey()      */     public Object getKey()     {       return key;     }     /**      * Get the value. Note: In an entrySet or entrySet.iterator, unless you      * can guarantee lack of concurrent modification,      * <tt>getValue</tt> <em>might</em> return null, reflecting the fact      * that the entry has been concurrently removed. However, there are no      * assurances that concurrent removals will be reflected using this      * method.      *       * @return the current value, or null if the entry has been detectably      *         removed.      */     public Object getValue()     {       return value;     }     /**      * Set the value of this entry. Note: In an entrySet or      * entrySet.iterator), unless you can guarantee lack of concurrent      * modification, <tt>setValue</tt> is not strictly guaranteed to      * actually replace the value field obtained via the <tt>get</tt>      * operation of the underlying hash table in multithreaded applications.      * If iterator-wide synchronization is not used, and any other      * concurrent <tt>put</tt> or <tt>remove</tt> operations occur,      * sometimes even to <em>other</em> entries, then this change is not      * guaranteed to be reflected in the hash table. (It might, or it might      * not. There are no assurances either way.)      *       * @param value      *            the new value.      * @return the previous value, or null if entry has been detectably      *         removed.      * @exception NullPointerException      *                if the value is <code>null</code>.      *       */     public Object setValue(Object value)     {       if (value == null)       {         throw new IllegalArgumentException("Value must not be null");       }       Object oldValue = this.value;       this.value = value;       return oldValue;     }     /**      * @see java.util.Map.Entry#equals(java.lang.Object)      */     public boolean equals(Object o)     {       if (!(o instanceof Map.Entry))       {         return false;       }       Map.Entry e = (Map.Entry)o;       return (key.equals(e.getKey()) && value.equals(e.getValue()));     }     /**      * @see java.util.Map.Entry#hashCode()      */     public int hashCode()     {       return key.hashCode() ^ value.hashCode();     }     /**      * @see java.lang.Object#toString()      */     public String toString()     {       return key + "=" + value;     }   }   protected class HashIterator implements Iterator, Enumeration   {     protected final Entry[] tab; // snapshot of table     protected int index; // current slot     protected Entry entry = null; // current node of slot     protected Object currentKey; // key for current node     protected Object currentValue; // value for current node     protected Entry lastReturned = null; // last node returned by next     protected HashIterator()     {       // force all segments to synch       synchronized (segments[0])       {         tab = table;       }       for (int i = 1; i < segments.length; ++i)       {         segments[i].synch();       }       index = tab.length - 1;     }     /**      * @see java.util.Enumeration#hasMoreElements()      */     public boolean hasMoreElements()     {       return hasNext();     }     /**      * @see java.util.Enumeration#nextElement()      */     public Object nextElement()     {       return next();     }     /**      * @see java.util.Iterator#hasNext()      */     public boolean hasNext()     {       /*        * currentkey and currentValue are set here to ensure that next()        * returns normally if hasNext() returns true. This avoids surprises        * especially when final element is removed during traversal --        * instead, we just ignore the removal during current traversal.        */       for (;;)       {         if (entry != null)         {           Object v = entry.value;           if (v != null)           {             currentKey = entry.key;             currentValue = v;             return true;           }           else           {             entry = entry.next;           }         }         while (entry == null && index >= 0)         {           entry = tab[index--];         }         if (entry == null)         {           currentKey = currentValue = null;           return false;         }       }     }     protected Object returnValueOfNext()     {       return entry;     }     /**      * @see java.util.Iterator#next()      */     public Object next()     {       if (currentKey == null && !hasNext())       {         throw new NoSuchElementException();       }       Object result = returnValueOfNext();       lastReturned = entry;       currentKey = currentValue = null;       entry = entry.next;       return result;     }     /**      * @see java.util.Iterator#remove()      */     public void remove()     {       if (lastReturned == null)       {         throw new IllegalStateException();       }       ConcurrentHashMap.this.remove(lastReturned.key);       lastReturned = null;     }   }   protected class KeyIterator extends HashIterator   {     protected Object returnValueOfNext()     {       return currentKey;     }   }   protected class ValueIterator extends HashIterator   {     protected Object returnValueOfNext()     {       return currentValue;     }   }   /**    * Save the state of the <tt>ConcurrentHashMap</tt> instance to a stream    * (i.e., serialize it).    * @param s     * @throws IOException     *     * @serialData An estimate of the table size, followed by the key (Object)    *             and value (Object) for each key-value mapping, followed by a    *             null pair. The key-value mappings are emitted in no    *             particular order.    */   private void writeObject(java.io.ObjectOutputStream s) throws IOException   {     // Write out the loadfactor, and any hidden stuff     s.defaultWriteObject();     // Write out capacity estimate. It is OK if this     // changes during the write, since it is only used by     // readObject to set initial capacity, to avoid needless resizings.     int cap;     synchronized (segments[0])     {       cap = table.length;     }     s.writeInt(cap);     // Write out keys and values (alternating)     for (int k = 0; k < segments.length; ++k)     {       Segment seg = segments[k];       Entry[] tab;       synchronized (seg)       {         tab = table;       }       for (int i = k; i < tab.length; i += segments.length)       {         for (Entry e = tab[i]; e != null; e = e.next)         {           s.writeObject(e.key);           s.writeObject(e.value);         }       }     }     s.writeObject(null);     s.writeObject(null);   }   /**    * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a stream    * (i.e., deserialize it).    * @param s     * @throws IOException     * @throws ClassNotFoundException     */   private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException   {     // Read in the threshold, loadfactor, and any hidden stuff     s.defaultReadObject();     int cap = s.readInt();     table = newTable(cap);     for (int i = 0; i < segments.length; ++i)     {       segments[i] = new Segment();     }     // Read the keys and values, and put the mappings in the table     for (;;)     {       Object key = s.readObject();       Object value = s.readObject();       if (key == null)       {         break;       }       put(key, value);     }   } }