ConcurrentHashMap.java Source code

Java tutorial

Introduction

Here is the source code for ConcurrentHashMap.java

Source

/*
 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);
        }
    }
}