Java并发编程规则:同步容器与并发容器

来源:互联网 发布:上海汇纳网络信息科技 编辑:程序博客网 时间:2024/05/15 12:22

同步性和并发性都是线程安全的知识,只要同时满足条件就可以编写支持并发线程安全的程序。

同步容器

首先,同步容器是线程安全的。Java中设计了同步容器的数据结构对象,如:Vector和HashTable。但必须说明的是,同步容器在复合操作(迭代、运算、逻辑处理等)时如果没有线程同步策略,那么程序就不是线程安全的。Java定义Vector是线程安全的。但是在多线程环境下,多个线程进行remove、get操作就会出现ArrayIndexOutOfBoundsException问题。修复此类问题的最好方式就是加锁。

复合操作不安全示例:

import java.util.Vector;public class VectorC1 {public static Object getLast(Vector vector){int index=vector.size()-1;return vector.get(index);}     public static void deleteLast(Vector vector){            int index=vector.size()-1;vector.remove(index);} }

修复复合操作示例:

import java.util.Vector;public class VectorC2 {public static Object getLast(Vector vector){synchronized (vector) {int index=vector.size()-1;return vector.get(index);}}     public static void deleteLast(Vector vector){    synchronized (vector) {            int index=vector.size()-1;vector.remove(index);}    } }

迭代操作不安全示例:

import java.util.Vector;public class VectorFor1 {public static void doService(Vector vector){for (int i = 0,j=vector.size(); i < j; i++) {doSomething(vector.get(i)); }}     public static void doSomething(Object obj){    } }

修复迭代操作不安全示例:

import java.util.Vector;public class VectorFor2 {public static void doService(Vector vector){synchronized (vector) {for (int i = 0,j=vector.size(); i < j; i++) {doSomething(vector.get(i)); }}}     public static void doSomething(Object obj){    } }
对Collection进行迭代的标准方式是使用Iterator。如果容器在迭代期间发生了改变,其他线程执行操作类似contains*,remove*(隐藏迭代器)等方法都有可能抛出ConcurrentModificationException异常。同步容器所有状态是串行访问,从而实现了线程安全,但是削弱了并发性,使程序的吞吐量降低。

并发容器

Java5.0通过几种并发容器来改进同步容器。用以替代同步哈希Map的设计,如:ConcurrentHashMap和ConcurrentMap。CopyOnWriteArrayList是List相应的同步实现。用并发容器替代同步容器,以很小的风险带了了扩展性显著的提高。

Java5.0同样提供了两个新的容器类型:Queue(null)和BlockingQueue(阻塞队列)。(Queue用于临时存储下一步执行等待的执行单元逻辑元素;FIFO先进先出的ConcurrentLinkedQueue;PriorityQueue优先顺序级别的队列。)

Java6.0中基于哈希Map的设计还新增了ConcurrentSkipListMap和ConcurrentSkipListSet,用来作为同步的SortedMap和SortedSet的替代品。

ConcurrentHashMap

ConcurrentHashMap具备更加细致的锁机制(分离锁),并且相比于HashTable和synchornizedMap,ConcurrentHashMap几乎没有什么劣势,因此大多数情况下用ConcurrentHashMap取代同步Map可以获得更好的可伸缩性。只有当你的程序需要独占访问加锁时,ConcurrentHashMap才无法胜任。

ConcurrentMap接口:

package java.util.concurrent;import java.util.Map;/** * A {@link java.util.Map} providing additional atomic * <tt>putIfAbsent</tt>, <tt>remove</tt>, and <tt>replace</tt> methods. * * <p>Memory consistency effects: As with other concurrent * collections, actions in a thread prior to placing an object into a * {@code ConcurrentMap} as a key or value * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> * actions subsequent to the access or removal of that object from * the {@code ConcurrentMap} in another thread. * * <p>This interface is a member of the * <a href="{@docRoot}/../technotes/guides/collections/index.html"> * Java Collections Framework</a>. * * @since 1.5 * @author Doug Lea * @param <K> the type of keys maintained by this map * @param <V> the type of mapped values */public interface ConcurrentMap<K, V> extends Map<K, V> {    /**     * If the specified key is not already associated     * with a value, associate it with the given value.     * This is equivalent to     * <pre>     *   if (!map.containsKey(key))     *       return map.put(key, value);     *   else     *       return map.get(key);</pre>     * except that the action is performed atomically.     *     * @param key key with which the specified value is to be associated     * @param value value to be associated with the specified key     * @return the previous value associated with the specified key, or     *         <tt>null</tt> if there was no mapping for the key.     *         (A <tt>null</tt> return can also indicate that the map     *         previously associated <tt>null</tt> with the key,     *         if the implementation supports null values.)     * @throws UnsupportedOperationException if the <tt>put</tt> operation     *         is not supported by this map     * @throws ClassCastException if the class of the specified key or value     *         prevents it from being stored in this map     * @throws NullPointerException if the specified key or value is null,     *         and this map does not permit null keys or values     * @throws IllegalArgumentException if some property of the specified key     *         or value prevents it from being stored in this map     *     */    V putIfAbsent(K key, V value);    /**     * Removes the entry for a key only if currently mapped to a given value.     * This is equivalent to     * <pre>     *   if (map.containsKey(key) && map.get(key).equals(value)) {     *       map.remove(key);     *       return true;     *   } else return false;</pre>     * except that the action is performed atomically.     *     * @param key key with which the specified value is associated     * @param value value expected to be associated with the specified key     * @return <tt>true</tt> if the value was removed     * @throws UnsupportedOperationException if the <tt>remove</tt> operation     *         is not supported by this map     * @throws ClassCastException if the key or value is of an inappropriate     *         type for this map     *         (<a href="../Collection.html#optional-restrictions">optional</a>)     * @throws NullPointerException if the specified key or value is null,     *         and this map does not permit null keys or values     *         (<a href="../Collection.html#optional-restrictions">optional</a>)     */    boolean remove(Object key, Object value);    /**     * Replaces the entry for a key only if currently mapped to a given value.     * This is equivalent to     * <pre>     *   if (map.containsKey(key) && map.get(key).equals(oldValue)) {     *       map.put(key, newValue);     *       return true;     *   } else return false;</pre>     * except that the action is performed atomically.     *     * @param key key with which the specified value is associated     * @param oldValue value expected to be associated with the specified key     * @param newValue value to be associated with the specified key     * @return <tt>true</tt> if the value was replaced     * @throws UnsupportedOperationException if the <tt>put</tt> operation     *         is not supported by this map     * @throws ClassCastException if the class of a specified key or value     *         prevents it from being stored in this map     * @throws NullPointerException if a specified key or value is null,     *         and this map does not permit null keys or values     * @throws IllegalArgumentException if some property of a specified key     *         or value prevents it from being stored in this map     */    boolean replace(K key, V oldValue, V newValue);    /**     * Replaces the entry for a key only if currently mapped to some value.     * This is equivalent to     * <pre>     *   if (map.containsKey(key)) {     *       return map.put(key, value);     *   } else return null;</pre>     * except that the action is performed atomically.     *     * @param key key with which the specified value is associated     * @param value value to be associated with the specified key     * @return the previous value associated with the specified key, or     *         <tt>null</tt> if there was no mapping for the key.     *         (A <tt>null</tt> return can also indicate that the map     *         previously associated <tt>null</tt> with the key,     *         if the implementation supports null values.)     * @throws UnsupportedOperationException if the <tt>put</tt> operation     *         is not supported by this map     * @throws ClassCastException if the class of the specified key or value     *         prevents it from being stored in this map     * @throws NullPointerException if the specified key or value is null,     *         and this map does not permit null keys or values     * @throws IllegalArgumentException if some property of the specified key     *         or value prevents it from being stored in this map     */    V replace(K key, V value);}

ConcurrentMap的ConcurrentHashMap实现:

package java.util.concurrent;import java.util.concurrent.locks.*;import java.util.*;import java.io.Serializable;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.ObjectStreamField;/** * A hash table supporting full concurrency of retrievals and * adjustable expected concurrency for updates. This class obeys the * same functional specification as {@link java.util.Hashtable}, and * includes versions of methods corresponding to each method of * <tt>Hashtable</tt>. However, even though all operations are * thread-safe, retrieval operations do <em>not</em> entail locking, * and there is <em>not</em> any support for locking the entire table * in a way that prevents all access.  This class is fully * interoperable with <tt>Hashtable</tt> in programs that rely on its * thread safety but not on its synchronization details. * * <p> Retrieval operations (including <tt>get</tt>) generally do not * block, so may overlap with update operations (including * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results * of the most recently <em>completed</em> update operations holding * upon their onset.  For aggregate operations such as <tt>putAll</tt> * and <tt>clear</tt>, concurrent retrievals may reflect insertion or * removal of only some entries.  Similarly, Iterators and * Enumerations return elements reflecting the state of the hash table * at some point at or since the creation of the iterator/enumeration. * They do <em>not</em> throw {@link ConcurrentModificationException}. * However, iterators are designed to be used by only one thread at a time. * * <p> The allowed concurrency among update operations is guided by * the optional <tt>concurrencyLevel</tt> constructor argument * (default <tt>16</tt>), which is used as a hint for internal sizing.  The * table is internally partitioned to try to permit the indicated * number of concurrent updates without contention. Because placement * in hash tables is essentially random, the actual concurrency will * vary.  Ideally, you should choose a value to accommodate as many * threads as will ever concurrently modify the table. Using a * significantly higher value than you need can waste space and time, * and a significantly lower value can lead to thread contention. But * overestimates and underestimates within an order of magnitude do * not usually have much noticeable impact. A value of one is * appropriate when it is known that only one thread will modify and * all others will only read. Also, resizing this or any other kind of * hash table is a relatively slow operation, so, when possible, it is * a good idea to provide estimates of expected table sizes in * constructors. * * <p>This class and its views and iterators implement all of the * <em>optional</em> methods of the {@link Map} and {@link Iterator} * interfaces. * * <p> Like {@link Hashtable} but unlike {@link HashMap}, this class * does <em>not</em> allow <tt>null</tt> to be used as a key or value. * * <p>This class is a member of the * <a href="{@docRoot}/../technotes/guides/collections/index.html"> * Java Collections Framework</a>. * * @since 1.5 * @author Doug Lea * @param <K> the type of keys maintained by this map * @param <V> the type of mapped values */public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>        implements ConcurrentMap<K, V>, Serializable {    private static final long serialVersionUID = 7249069246763182397L;    /*     * The basic strategy is to subdivide the table among Segments,     * each of which itself is a concurrently readable hash table.  To     * reduce footprint, all but one segments are constructed only     * when first needed (see ensureSegment). To maintain visibility     * in the presence of lazy construction, accesses to segments as     * well as elements of segment's table must use volatile access,     * which is done via Unsafe within methods segmentAt etc     * below. These provide the functionality of AtomicReferenceArrays     * but reduce the levels of indirection. Additionally,     * volatile-writes of table elements and entry "next" fields     * within locked operations use the cheaper "lazySet" forms of     * writes (via putOrderedObject) because these writes are always     * followed by lock releases that maintain sequential consistency     * of table updates.     *     * Historical note: The previous version of this class relied     * heavily on "final" fields, which avoided some volatile reads at     * the expense of a large initial footprint.  Some remnants of     * that design (including forced construction of segment 0) exist     * to ensure serialization compatibility.     */    /* ---------------- Constants -------------- */    /**     * The default initial capacity for this table,     * used when not otherwise specified in a constructor.     */    static final int DEFAULT_INITIAL_CAPACITY = 16;    /**     * The default load factor for this table, used when not     * otherwise specified in a constructor.     */    static final float DEFAULT_LOAD_FACTOR = 0.75f;    /**     * The default concurrency level for this table, used when not     * otherwise specified in a constructor.     */    static final int DEFAULT_CONCURRENCY_LEVEL = 16;    /**     * 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 to ensure that entries are indexable     * using ints.     */    static final int MAXIMUM_CAPACITY = 1 << 30;    /**     * The minimum capacity for per-segment tables.  Must be a power     * of two, at least two to avoid immediate resizing on next use     * after lazy construction.     */    static final int MIN_SEGMENT_TABLE_CAPACITY = 2;    /**     * The maximum number of segments to allow; used to bound     * constructor arguments. Must be power of two less than 1 << 24.     */    static final int MAX_SEGMENTS = 1 << 16; // slightly conservative    /**     * Number of unsynchronized retries in size and containsValue     * methods before resorting to locking. This is used to avoid     * unbounded retries if tables undergo continuous modification     * which would make it impossible to obtain an accurate result.     */    static final int RETRIES_BEFORE_LOCK = 2;    /* ---------------- Fields -------------- */    /**     * holds values which can't be initialized until after VM is booted.     */    private static class Holder {        /**        * Enable alternative hashing of String keys?        *        * <p>Unlike the other hash map implementations we do not implement a        * threshold for regulating whether alternative hashing is used for        * String keys. Alternative hashing is either enabled for all instances        * or disabled for all instances.        */        static final boolean ALTERNATIVE_HASHING;        static {            // Use the "threshold" system property even though our threshold            // behaviour is "ON" or "OFF".            String altThreshold = java.security.AccessController.doPrivileged(                new sun.security.action.GetPropertyAction(                    "jdk.map.althashing.threshold"));            int threshold;            try {                threshold = (null != altThreshold)                        ? Integer.parseInt(altThreshold)                        : Integer.MAX_VALUE;                // disable alternative hashing if -1                if (threshold == -1) {                    threshold = Integer.MAX_VALUE;                }                if (threshold < 0) {                    throw new IllegalArgumentException("value must be positive integer.");                }            } catch(IllegalArgumentException failed) {                throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed);            }            ALTERNATIVE_HASHING = threshold <= MAXIMUM_CAPACITY;        }    }    /**     * A randomizing value associated with this instance that is applied to     * hash code of keys to make hash collisions harder to find.     */    private transient final int hashSeed = randomHashSeed(this);    private static int randomHashSeed(ConcurrentHashMap instance) {        if (sun.misc.VM.isBooted() && Holder.ALTERNATIVE_HASHING) {            return sun.misc.Hashing.randomHashSeed(instance);        }        return 0;    }    /**     * Mask value for indexing into segments. The upper bits of a     * key's hash code are used to choose the segment.     */    final int segmentMask;    /**     * Shift value for indexing within segments.     */    final int segmentShift;    /**     * The segments, each of which is a specialized hash table.     */    final Segment<K,V>[] segments;    transient Set<K> keySet;    transient Set<Map.Entry<K,V>> entrySet;    transient Collection<V> values;    /**     * ConcurrentHashMap list entry. Note that this is never exported     * out as a user-visible Map.Entry.     */    static final class HashEntry<K,V> {        final int hash;        final K key;        volatile V value;        volatile HashEntry<K,V> next;        HashEntry(int hash, K key, V value, HashEntry<K,V> next) {            this.hash = hash;            this.key = key;            this.value = value;            this.next = next;        }        /**         * Sets next field with volatile write semantics.  (See above         * about use of putOrderedObject.)         */        final void setNext(HashEntry<K,V> n) {            UNSAFE.putOrderedObject(this, nextOffset, n);        }        // Unsafe mechanics        static final sun.misc.Unsafe UNSAFE;        static final long nextOffset;        static {            try {                UNSAFE = sun.misc.Unsafe.getUnsafe();                Class k = HashEntry.class;                nextOffset = UNSAFE.objectFieldOffset                    (k.getDeclaredField("next"));            } catch (Exception e) {                throw new Error(e);            }        }    }    /**     * Gets the ith element of given table (if nonnull) with volatile     * read semantics. Note: This is manually integrated into a few     * performance-sensitive methods to reduce call overhead.     */    @SuppressWarnings("unchecked")    static final <K,V> HashEntry<K,V> entryAt(HashEntry<K,V>[] tab, int i) {        return (tab == null) ? null :            (HashEntry<K,V>) UNSAFE.getObjectVolatile            (tab, ((long)i << TSHIFT) + TBASE);    }    /**     * Sets the ith element of given table, with volatile write     * semantics. (See above about use of putOrderedObject.)     */    static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,                                       HashEntry<K,V> e) {        UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);    }    /**     * Applies a supplemental hash function to a given hashCode, which     * defends against poor quality hash functions.  This is critical     * because ConcurrentHashMap uses power-of-two length hash tables,     * that otherwise encounter collisions for hashCodes that do not     * differ in lower or upper bits.     */    private int hash(Object k) {        int h = hashSeed;        if ((0 != h) && (k instanceof String)) {            return sun.misc.Hashing.stringHash32((String) k);        }        h ^= k.hashCode();        // Spread bits to regularize both segment and index locations,        // using variant of single-word Wang/Jenkins hash.        h += (h <<  15) ^ 0xffffcd7d;        h ^= (h >>> 10);        h += (h <<   3);        h ^= (h >>>  6);        h += (h <<   2) + (h << 14);        return h ^ (h >>> 16);    }    /**     * Segments are specialized versions of hash tables.  This     * subclasses from ReentrantLock opportunistically, just to     * simplify some locking and avoid separate construction.     */    static final class Segment<K,V> extends ReentrantLock implements Serializable {        /*         * Segments maintain a table of entry lists that are always         * kept in a consistent state, so can be read (via volatile         * reads of segments and tables) without locking.  This         * requires replicating nodes when necessary during table         * resizing, so the old lists can be traversed by readers         * still using old version of table.         *         * This class defines only mutative methods requiring locking.         * Except as noted, the methods of this class perform the         * per-segment versions of ConcurrentHashMap methods.  (Other         * methods are integrated directly into ConcurrentHashMap         * methods.) These mutative methods use a form of controlled         * spinning on contention via methods scanAndLock and         * scanAndLockForPut. These intersperse tryLocks with         * traversals to locate nodes.  The main benefit is to absorb         * cache misses (which are very common for hash tables) while         * obtaining locks so that traversal is faster once         * acquired. We do not actually use the found nodes since they         * must be re-acquired under lock anyway to ensure sequential         * consistency of updates (and in any case may be undetectably         * stale), but they will normally be much faster to re-locate.         * Also, scanAndLockForPut speculatively creates a fresh node         * to use in put if no node is found.         */        private static final long serialVersionUID = 2249069246763182397L;        /**         * The maximum number of times to tryLock in a prescan before         * possibly blocking on acquire in preparation for a locked         * segment operation. On multiprocessors, using a bounded         * number of retries maintains cache acquired while locating         * nodes.         */        static final int MAX_SCAN_RETRIES =            Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;        /**         * The per-segment table. Elements are accessed via         * entryAt/setEntryAt providing volatile semantics.         */        transient volatile HashEntry<K,V>[] table;        /**         * The number of elements. Accessed only either within locks         * or among other volatile reads that maintain visibility.         */        transient int count;        /**         * The total number of mutative operations in this segment.         * Even though this may overflows 32 bits, it provides         * sufficient accuracy for stability checks in CHM isEmpty()         * and size() methods.  Accessed only either within locks or         * among other volatile reads that maintain visibility.         */        transient int modCount;        /**         * The table is rehashed when its size exceeds this threshold.         * (The value of this field is always <tt>(int)(capacity *         * loadFactor)</tt>.)         */        transient int threshold;        /**         * The load factor for the hash table.  Even though this value         * is same for all segments, it is replicated to avoid needing         * links to outer object.         * @serial         */        final float loadFactor;        Segment(float lf, int threshold, HashEntry<K,V>[] tab) {            this.loadFactor = lf;            this.threshold = threshold;            this.table = tab;        }        final V put(K key, int hash, V value, boolean onlyIfAbsent) {            HashEntry<K,V> node = tryLock() ? null :                scanAndLockForPut(key, hash, value);            V oldValue;            try {                HashEntry<K,V>[] tab = table;                int index = (tab.length - 1) & hash;                HashEntry<K,V> first = entryAt(tab, index);                for (HashEntry<K,V> e = first;;) {                    if (e != null) {                        K k;                        if ((k = e.key) == key ||                            (e.hash == hash && key.equals(k))) {                            oldValue = e.value;                            if (!onlyIfAbsent) {                                e.value = value;                                ++modCount;                            }                            break;                        }                        e = e.next;                    }                    else {                        if (node != null)                            node.setNext(first);                        else                            node = new HashEntry<K,V>(hash, key, value, first);                        int c = count + 1;                        if (c > threshold && tab.length < MAXIMUM_CAPACITY)                            rehash(node);                        else                            setEntryAt(tab, index, node);                        ++modCount;                        count = c;                        oldValue = null;                        break;                    }                }            } finally {                unlock();            }            return oldValue;        }        /**         * Doubles size of table and repacks entries, also adding the         * given node to new table         */        @SuppressWarnings("unchecked")        private void rehash(HashEntry<K,V> node) {            /*             * Reclassify nodes in each list to new table.  Because we             * are using power-of-two expansion, the elements from             * each bin must either stay at same index, or move with a             * power of two offset. We eliminate unnecessary node             * creation by catching cases where old nodes can be             * reused because their next fields won't change.             * Statistically, at the default threshold, only about             * one-sixth of them need cloning when a table             * doubles. 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             * concurrently traversing table. Entry accesses use plain             * array indexing because they are followed by volatile             * table write.             */            HashEntry<K,V>[] oldTable = table;            int oldCapacity = oldTable.length;            int newCapacity = oldCapacity << 1;            threshold = (int)(newCapacity * loadFactor);            HashEntry<K,V>[] newTable =                (HashEntry<K,V>[]) new HashEntry[newCapacity];            int sizeMask = newCapacity - 1;            for (int i = 0; i < oldCapacity ; i++) {                HashEntry<K,V> e = oldTable[i];                if (e != null) {                    HashEntry<K,V> next = e.next;                    int idx = e.hash & sizeMask;                    if (next == null)   //  Single node on list                        newTable[idx] = e;                    else { // Reuse consecutive sequence at same slot                        HashEntry<K,V> lastRun = e;                        int lastIdx = idx;                        for (HashEntry<K,V> last = next;                             last != null;                             last = last.next) {                            int k = last.hash & sizeMask;                            if (k != lastIdx) {                                lastIdx = k;                                lastRun = last;                            }                        }                        newTable[lastIdx] = lastRun;                        // Clone remaining nodes                        for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {                            V v = p.value;                            int h = p.hash;                            int k = h & sizeMask;                            HashEntry<K,V> n = newTable[k];                            newTable[k] = new HashEntry<K,V>(h, p.key, v, n);                        }                    }                }            }            int nodeIndex = node.hash & sizeMask; // add the new node            node.setNext(newTable[nodeIndex]);            newTable[nodeIndex] = node;            table = newTable;        }        /**         * Scans for a node containing given key while trying to         * acquire lock, creating and returning one if not found. Upon         * return, guarantees that lock is held. UNlike in most         * methods, calls to method equals are not screened: Since         * traversal speed doesn't matter, we might as well help warm         * up the associated code and accesses as well.         *         * @return a new node if key not found, else null         */        private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {            HashEntry<K,V> first = entryForHash(this, hash);            HashEntry<K,V> e = first;            HashEntry<K,V> node = null;            int retries = -1; // negative while locating node            while (!tryLock()) {                HashEntry<K,V> f; // to recheck first below                if (retries < 0) {                    if (e == null) {                        if (node == null) // speculatively create node                            node = new HashEntry<K,V>(hash, key, value, null);                        retries = 0;                    }                    else if (key.equals(e.key))                        retries = 0;                    else                        e = e.next;                }                else if (++retries > MAX_SCAN_RETRIES) {                    lock();                    break;                }                else if ((retries & 1) == 0 &&                         (f = entryForHash(this, hash)) != first) {                    e = first = f; // re-traverse if entry changed                    retries = -1;                }            }            return node;        }        /**         * Scans for a node containing the given key while trying to         * acquire lock for a remove or replace operation. Upon         * return, guarantees that lock is held.  Note that we must         * lock even if the key is not found, to ensure sequential         * consistency of updates.         */        private void scanAndLock(Object key, int hash) {            // similar to but simpler than scanAndLockForPut            HashEntry<K,V> first = entryForHash(this, hash);            HashEntry<K,V> e = first;            int retries = -1;            while (!tryLock()) {                HashEntry<K,V> f;                if (retries < 0) {                    if (e == null || key.equals(e.key))                        retries = 0;                    else                        e = e.next;                }                else if (++retries > MAX_SCAN_RETRIES) {                    lock();                    break;                }                else if ((retries & 1) == 0 &&                         (f = entryForHash(this, hash)) != first) {                    e = first = f;                    retries = -1;                }            }        }        /**         * Remove; match on key only if value null, else match both.         */        final V remove(Object key, int hash, Object value) {            if (!tryLock())                scanAndLock(key, hash);            V oldValue = null;            try {                HashEntry<K,V>[] tab = table;                int index = (tab.length - 1) & hash;                HashEntry<K,V> e = entryAt(tab, index);                HashEntry<K,V> pred = null;                while (e != null) {                    K k;                    HashEntry<K,V> next = e.next;                    if ((k = e.key) == key ||                        (e.hash == hash && key.equals(k))) {                        V v = e.value;                        if (value == null || value == v || value.equals(v)) {                            if (pred == null)                                setEntryAt(tab, index, next);                            else                                pred.setNext(next);                            ++modCount;                            --count;                            oldValue = v;                        }                        break;                    }                    pred = e;                    e = next;                }            } finally {                unlock();            }            return oldValue;        }        final boolean replace(K key, int hash, V oldValue, V newValue) {            if (!tryLock())                scanAndLock(key, hash);            boolean replaced = false;            try {                HashEntry<K,V> e;                for (e = entryForHash(this, hash); e != null; e = e.next) {                    K k;                    if ((k = e.key) == key ||                        (e.hash == hash && key.equals(k))) {                        if (oldValue.equals(e.value)) {                            e.value = newValue;                            ++modCount;                            replaced = true;                        }                        break;                    }                }            } finally {                unlock();            }            return replaced;        }        final V replace(K key, int hash, V value) {            if (!tryLock())                scanAndLock(key, hash);            V oldValue = null;            try {                HashEntry<K,V> e;                for (e = entryForHash(this, hash); e != null; e = e.next) {                    K k;                    if ((k = e.key) == key ||                        (e.hash == hash && key.equals(k))) {                        oldValue = e.value;                        e.value = value;                        ++modCount;                        break;                    }                }            } finally {                unlock();            }            return oldValue;        }        final void clear() {            lock();            try {                HashEntry<K,V>[] tab = table;                for (int i = 0; i < tab.length ; i++)                    setEntryAt(tab, i, null);                ++modCount;                count = 0;            } finally {                unlock();            }        }    }    // Accessing segments    /**     * Gets the jth element of given segment array (if nonnull) with     * volatile element access semantics via Unsafe. (The null check     * can trigger harmlessly only during deserialization.) Note:     * because each element of segments array is set only once (using     * fully ordered writes), some performance-sensitive methods rely     * on this method only as a recheck upon null reads.     */    @SuppressWarnings("unchecked")    static final <K,V> Segment<K,V> segmentAt(Segment<K,V>[] ss, int j) {        long u = (j << SSHIFT) + SBASE;        return ss == null ? null :            (Segment<K,V>) UNSAFE.getObjectVolatile(ss, u);    }    /**     * Returns the segment for the given index, creating it and     * recording in segment table (via CAS) if not already present.     *     * @param k the index     * @return the segment     */    @SuppressWarnings("unchecked")    private Segment<K,V> ensureSegment(int k) {        final Segment<K,V>[] ss = this.segments;        long u = (k << SSHIFT) + SBASE; // raw offset        Segment<K,V> seg;        if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {            Segment<K,V> proto = ss[0]; // use segment 0 as prototype            int cap = proto.table.length;            float lf = proto.loadFactor;            int threshold = (int)(cap * lf);            HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap];            if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))                == null) { // recheck                Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);                while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))                       == null) {                    if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))                        break;                }            }        }        return seg;    }    // Hash-based segment and entry accesses    /**     * Get the segment for the given hash     */    @SuppressWarnings("unchecked")    private Segment<K,V> segmentForHash(int h) {        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;        return (Segment<K,V>) UNSAFE.getObjectVolatile(segments, u);    }    /**     * Gets the table entry for the given segment and hash     */    @SuppressWarnings("unchecked")    static final <K,V> HashEntry<K,V> entryForHash(Segment<K,V> seg, int h) {        HashEntry<K,V>[] tab;        return (seg == null || (tab = seg.table) == null) ? null :            (HashEntry<K,V>) UNSAFE.getObjectVolatile            (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);    }    /* ---------------- Public operations -------------- */    /**     * Creates a new, empty map with the specified initial     * capacity, load factor and concurrency level.     *     * @param initialCapacity the initial capacity. The implementation     * performs internal sizing to accommodate this many elements.     * @param loadFactor  the load factor threshold, used to control resizing.     * Resizing may be performed when the average number of elements per     * bin exceeds this threshold.     * @param concurrencyLevel the estimated number of concurrently     * updating threads. The implementation performs internal sizing     * to try to accommodate this many threads.     * @throws IllegalArgumentException if the initial capacity is     * negative or the load factor or concurrencyLevel are     * nonpositive.     */    @SuppressWarnings("unchecked")    public ConcurrentHashMap(int initialCapacity,                             float loadFactor, int concurrencyLevel) {        if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)            throw new IllegalArgumentException();        if (concurrencyLevel > MAX_SEGMENTS)            concurrencyLevel = MAX_SEGMENTS;        // Find power-of-two sizes best matching arguments        int sshift = 0;        int ssize = 1;        while (ssize < concurrencyLevel) {            ++sshift;            ssize <<= 1;        }        this.segmentShift = 32 - sshift;        this.segmentMask = ssize - 1;        if (initialCapacity > MAXIMUM_CAPACITY)            initialCapacity = MAXIMUM_CAPACITY;        int c = initialCapacity / ssize;        if (c * ssize < initialCapacity)            ++c;        int cap = MIN_SEGMENT_TABLE_CAPACITY;        while (cap < c)            cap <<= 1;        // create segments and segments[0]        Segment<K,V> s0 =            new Segment<K,V>(loadFactor, (int)(cap * loadFactor),                             (HashEntry<K,V>[])new HashEntry[cap]);        Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];        UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]        this.segments = ss;    }    /**     * Creates a new, empty map with the specified initial capacity     * and load factor and with the default concurrencyLevel (16).     *     * @param initialCapacity The implementation performs internal     * sizing to accommodate this many elements.     * @param loadFactor  the load factor threshold, used to control resizing.     * Resizing may be performed when the average number of elements per     * bin exceeds this threshold.     * @throws IllegalArgumentException if the initial capacity of     * elements is negative or the load factor is nonpositive     *     * @since 1.6     */    public ConcurrentHashMap(int initialCapacity, float loadFactor) {        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);    }    /**     * Creates a new, empty map with the specified initial capacity,     * and with default load factor (0.75) and concurrencyLevel (16).     *     * @param initialCapacity the initial capacity. The implementation     * performs internal sizing to accommodate this many elements.     * @throws IllegalArgumentException if the initial capacity of     * elements is negative.     */    public ConcurrentHashMap(int initialCapacity) {        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);    }    /**     * Creates a new, empty map with a default initial capacity (16),     * load factor (0.75) and concurrencyLevel (16).     */    public ConcurrentHashMap() {        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);    }    /**     * Creates a new map with the same mappings as the given map.     * The map is created with a capacity of 1.5 times the number     * of mappings in the given map or 16 (whichever is greater),     * and a default load factor (0.75) and concurrencyLevel (16).     *     * @param m the map     */    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,                      DEFAULT_INITIAL_CAPACITY),             DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);        putAll(m);    }    /**     * 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() {        /*         * Sum per-segment modCounts to avoid mis-reporting when         * elements are concurrently added and removed in one segment         * while checking another, in which case the table was never         * actually empty at any point. (The sum ensures accuracy up         * through at least 1<<31 per-segment modifications before         * recheck.)  Methods size() and containsValue() use similar         * constructions for stability checks.         */        long sum = 0L;        final Segment<K,V>[] segments = this.segments;        for (int j = 0; j < segments.length; ++j) {            Segment<K,V> seg = segmentAt(segments, j);            if (seg != null) {                if (seg.count != 0)                    return false;                sum += seg.modCount;            }        }        if (sum != 0L) { // recheck unless no modifications            for (int j = 0; j < segments.length; ++j) {                Segment<K,V> seg = segmentAt(segments, j);                if (seg != null) {                    if (seg.count != 0)                        return false;                    sum -= seg.modCount;                }            }            if (sum != 0L)                return false;        }        return true;    }    /**     * Returns the number of key-value mappings in this map.  If the     * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns     * <tt>Integer.MAX_VALUE</tt>.     *     * @return the number of key-value mappings in this map     */    public int size() {        // Try a few times to get accurate count. On failure due to        // continuous async changes in table, resort to locking.        final Segment<K,V>[] segments = this.segments;        int size;        boolean overflow; // true if size overflows 32 bits        long sum;         // sum of modCounts        long last = 0L;   // previous sum        int retries = -1; // first iteration isn't retry        try {            for (;;) {                if (retries++ == RETRIES_BEFORE_LOCK) {                    for (int j = 0; j < segments.length; ++j)                        ensureSegment(j).lock(); // force creation                }                sum = 0L;                size = 0;                overflow = false;                for (int j = 0; j < segments.length; ++j) {                    Segment<K,V> seg = segmentAt(segments, j);                    if (seg != null) {                        sum += seg.modCount;                        int c = seg.count;                        if (c < 0 || (size += c) < 0)                            overflow = true;                    }                }                if (sum == last)                    break;                last = sum;            }        } finally {            if (retries > RETRIES_BEFORE_LOCK) {                for (int j = 0; j < segments.length; ++j)                    segmentAt(segments, j).unlock();            }        }        return overflow ? Integer.MAX_VALUE : size;    }    /**     * Returns the value to which the specified key is mapped,     * or {@code null} if this map contains no mapping for the key.     *     * <p>More formally, if this map contains a mapping from a key     * {@code k} to a value {@code v} such that {@code key.equals(k)},     * then this method returns {@code v}; otherwise it returns     * {@code null}.  (There can be at most one such mapping.)     *     * @throws NullPointerException if the specified key is null     */    public V get(Object key) {        Segment<K,V> s; // manually integrate access methods to reduce overhead        HashEntry<K,V>[] tab;        int h = hash(key);        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&            (tab = s.table) != null) {            for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile                     (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);                 e != null; e = e.next) {                K k;                if ((k = e.key) == key || (e.hash == h && key.equals(k)))                    return e.value;            }        }        return null;    }    /**     * Tests if the specified object is a key in this table.     *     * @param  key   possible key     * @return <tt>true</tt> if and only if the specified object     *         is a key in this table, as determined by the     *         <tt>equals</tt> method; <tt>false</tt> otherwise.     * @throws NullPointerException if the specified key is null     */    @SuppressWarnings("unchecked")    public boolean containsKey(Object key) {        Segment<K,V> s; // same as get() except no need for volatile value read        HashEntry<K,V>[] tab;        int h = hash(key);        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&            (tab = s.table) != null) {            for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile                     (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);                 e != null; e = e.next) {                K k;                if ((k = e.key) == key || (e.hash == h && key.equals(k)))                    return true;            }        }        return false;    }    /**     * 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     * @throws NullPointerException if the specified value is null     */    public boolean containsValue(Object value) {        // Same idea as size()        if (value == null)            throw new NullPointerException();        final Segment<K,V>[] segments = this.segments;        boolean found = false;        long last = 0;        int retries = -1;        try {            outer: for (;;) {                if (retries++ == RETRIES_BEFORE_LOCK) {                    for (int j = 0; j < segments.length; ++j)                        ensureSegment(j).lock(); // force creation                }                long hashSum = 0L;                int sum = 0;                for (int j = 0; j < segments.length; ++j) {                    HashEntry<K,V>[] tab;                    Segment<K,V> seg = segmentAt(segments, j);                    if (seg != null && (tab = seg.table) != null) {                        for (int i = 0 ; i < tab.length; i++) {                            HashEntry<K,V> e;                            for (e = entryAt(tab, i); e != null; e = e.next) {                                V v = e.value;                                if (v != null && value.equals(v)) {                                    found = true;                                    break outer;                                }                            }                        }                        sum += seg.modCount;                    }                }                if (retries > 0 && sum == last)                    break;                last = sum;            }        } finally {            if (retries > RETRIES_BEFORE_LOCK) {                for (int j = 0; j < segments.length; ++j)                    segmentAt(segments, j).unlock();            }        }        return found;    }    /**     * Legacy method testing if some key maps into the specified value     * in this table.  This method is identical in functionality to     * {@link #containsValue}, and exists solely to ensure     * full compatibility with class {@link java.util.Hashtable},     * which supported this method prior to introduction of the     * Java Collections framework.     * @param  value a value to search for     * @return <tt>true</tt> if and only if some key maps to the     *         <tt>value</tt> argument in this table as     *         determined by the <tt>equals</tt> method;     *         <tt>false</tt> otherwise     * @throws NullPointerException if the specified value is null     */    public boolean contains(Object value) {        return containsValue(value);    }    /**     * Maps the specified key to the specified value in this table.     * Neither the key nor the value can be null.     *     * <p> The value can be retrieved by calling the <tt>get</tt> method     * with a key that is equal to the original key.     *     * @param key key with which the specified value is to be associated     * @param value value to be associated with the specified key     * @return the previous value associated with <tt>key</tt>, or     *         <tt>null</tt> if there was no mapping for <tt>key</tt>     * @throws NullPointerException if the specified key or value is null     */    @SuppressWarnings("unchecked")    public V put(K key, V value) {        Segment<K,V> s;        if (value == null)            throw new NullPointerException();        int hash = hash(key);        int j = (hash >>> segmentShift) & segmentMask;        if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck             (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment            s = ensureSegment(j);        return s.put(key, hash, value, false);    }    /**     * {@inheritDoc}     *     * @return the previous value associated with the specified key,     *         or <tt>null</tt> if there was no mapping for the key     * @throws NullPointerException if the specified key or value is null     */    @SuppressWarnings("unchecked")    public V putIfAbsent(K key, V value) {        Segment<K,V> s;        if (value == null)            throw new NullPointerException();        int hash = hash(key);        int j = (hash >>> segmentShift) & segmentMask;        if ((s = (Segment<K,V>)UNSAFE.getObject             (segments, (j << SSHIFT) + SBASE)) == null)            s = ensureSegment(j);        return s.put(key, hash, value, true);    }    /**     * 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 m mappings to be stored in this map     */    public void putAll(Map<? extends K, ? extends V> m) {        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())            put(e.getKey(), e.getValue());    }    /**     * Removes the key (and its corresponding value) from this map.     * This method does nothing if the key is not in the map.     *     * @param  key the key that needs to be removed     * @return the previous value associated with <tt>key</tt>, or     *         <tt>null</tt> if there was no mapping for <tt>key</tt>     * @throws NullPointerException if the specified key is null     */    public V remove(Object key) {        int hash = hash(key);        Segment<K,V> s = segmentForHash(hash);        return s == null ? null : s.remove(key, hash, null);    }    /**     * {@inheritDoc}     *     * @throws NullPointerException if the specified key is null     */    public boolean remove(Object key, Object value) {        int hash = hash(key);        Segment<K,V> s;        return value != null && (s = segmentForHash(hash)) != null &&            s.remove(key, hash, value) != null;    }    /**     * {@inheritDoc}     *     * @throws NullPointerException if any of the arguments are null     */    public boolean replace(K key, V oldValue, V newValue) {        int hash = hash(key);        if (oldValue == null || newValue == null)            throw new NullPointerException();        Segment<K,V> s = segmentForHash(hash);        return s != null && s.replace(key, hash, oldValue, newValue);    }    /**     * {@inheritDoc}     *     * @return the previous value associated with the specified key,     *         or <tt>null</tt> if there was no mapping for the key     * @throws NullPointerException if the specified key or value is null     */    public V replace(K key, V value) {        int hash = hash(key);        if (value == null)            throw new NullPointerException();        Segment<K,V> s = segmentForHash(hash);        return s == null ? null : s.replace(key, hash, value);    }    /**     * Removes all of the mappings from this map.     */    public void clear() {        final Segment<K,V>[] segments = this.segments;        for (int j = 0; j < segments.length; ++j) {            Segment<K,V> s = segmentAt(segments, j);            if (s != null)                s.clear();        }    }    /**     * Returns a {@link 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.     *     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator     * that will never throw {@link ConcurrentModificationException},     * and guarantees to traverse elements as they existed upon     * construction of the iterator, and may (but is not guaranteed to)     * reflect any modifications subsequent to construction.     */    public Set<K> keySet() {        Set<K> ks = keySet;        return (ks != null) ? ks : (keySet = new KeySet());    }    /**     * Returns a {@link 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.     *     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator     * that will never throw {@link ConcurrentModificationException},     * and guarantees to traverse elements as they existed upon     * construction of the iterator, and may (but is not guaranteed to)     * reflect any modifications subsequent to construction.     */    public Collection<V> values() {        Collection<V> vs = values;        return (vs != null) ? vs : (values = new Values());    }    /**     * Returns a {@link Set} view of the mappings 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 the 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.     *     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator     * that will never throw {@link ConcurrentModificationException},     * and guarantees to traverse elements as they existed upon     * construction of the iterator, and may (but is not guaranteed to)     * reflect any modifications subsequent to construction.     */    public Set<Map.Entry<K,V>> entrySet() {        Set<Map.Entry<K,V>> es = entrySet;        return (es != null) ? es : (entrySet = new EntrySet());    }    /**     * Returns an enumeration of the keys in this table.     *     * @return an enumeration of the keys in this table     * @see #keySet()     */    public Enumeration<K> keys() {        return new KeyIterator();    }    /**     * Returns an enumeration of the values in this table.     *     * @return an enumeration of the values in this table     * @see #values()     */    public Enumeration<V> elements() {        return new ValueIterator();    }    /* ---------------- Iterator Support -------------- */    abstract class HashIterator {        int nextSegmentIndex;        int nextTableIndex;        HashEntry<K,V>[] currentTable;        HashEntry<K, V> nextEntry;        HashEntry<K, V> lastReturned;        HashIterator() {            nextSegmentIndex = segments.length - 1;            nextTableIndex = -1;            advance();        }        /**         * Set nextEntry to first node of next non-empty table         * (in backwards order, to simplify checks).         */        final void advance() {            for (;;) {                if (nextTableIndex >= 0) {                    if ((nextEntry = entryAt(currentTable,                                             nextTableIndex--)) != null)                        break;                }                else if (nextSegmentIndex >= 0) {                    Segment<K,V> seg = segmentAt(segments, nextSegmentIndex--);                    if (seg != null && (currentTable = seg.table) != null)                        nextTableIndex = currentTable.length - 1;                }                else                    break;            }        }        final HashEntry<K,V> nextEntry() {            HashEntry<K,V> e = nextEntry;            if (e == null)                throw new NoSuchElementException();            lastReturned = e; // cannot assign until after null check            if ((nextEntry = e.next) == null)                advance();            return e;        }        public final boolean hasNext() { return nextEntry != null; }        public final boolean hasMoreElements() { return nextEntry != null; }        public final void remove() {            if (lastReturned == null)                throw new IllegalStateException();            ConcurrentHashMap.this.remove(lastReturned.key);            lastReturned = null;        }    }    final class KeyIterator        extends HashIterator        implements Iterator<K>, Enumeration<K>    {        public final K next()        { return super.nextEntry().key; }        public final K nextElement() { return super.nextEntry().key; }    }    final class ValueIterator        extends HashIterator        implements Iterator<V>, Enumeration<V>    {        public final V next()        { return super.nextEntry().value; }        public final V nextElement() { return super.nextEntry().value; }    }    /**     * Custom Entry class used by EntryIterator.next(), that relays     * setValue changes to the underlying map.     */    final class WriteThroughEntry        extends AbstractMap.SimpleEntry<K,V>    {        WriteThroughEntry(K k, V v) {            super(k,v);        }        /**         * Set our entry's value and write through to the map. The         * value to return is somewhat arbitrary here. Since a         * WriteThroughEntry does not necessarily track asynchronous         * changes, the most recent "previous" value could be         * different from what we return (or could even have been         * removed in which case the put will re-establish). We do not         * and cannot guarantee more.         */        public V setValue(V value) {            if (value == null) throw new NullPointerException();            V v = super.setValue(value);            ConcurrentHashMap.this.put(getKey(), value);            return v;        }    }    final class EntryIterator        extends HashIterator        implements Iterator<Entry<K,V>>    {        public Map.Entry<K,V> next() {            HashEntry<K,V> e = super.nextEntry();            return new WriteThroughEntry(e.key, e.value);        }    }    final class KeySet extends AbstractSet<K> {        public Iterator<K> iterator() {            return new KeyIterator();        }        public int size() {            return ConcurrentHashMap.this.size();        }        public boolean isEmpty() {            return ConcurrentHashMap.this.isEmpty();        }        public boolean contains(Object o) {            return ConcurrentHashMap.this.containsKey(o);        }        public boolean remove(Object o) {            return ConcurrentHashMap.this.remove(o) != null;        }        public void clear() {            ConcurrentHashMap.this.clear();        }    }    final class Values extends AbstractCollection<V> {        public Iterator<V> iterator() {            return new ValueIterator();        }        public int size() {            return ConcurrentHashMap.this.size();        }        public boolean isEmpty() {            return ConcurrentHashMap.this.isEmpty();        }        public boolean contains(Object o) {            return ConcurrentHashMap.this.containsValue(o);        }        public void clear() {            ConcurrentHashMap.this.clear();        }    }    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {        public Iterator<Map.Entry<K,V>> iterator() {            return new EntryIterator();        }        public boolean contains(Object o) {            if (!(o instanceof Map.Entry))                return false;            Map.Entry<?,?> e = (Map.Entry<?,?>)o;            V v = ConcurrentHashMap.this.get(e.getKey());            return v != null && v.equals(e.getValue());        }        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());        }        public int size() {            return ConcurrentHashMap.this.size();        }        public boolean isEmpty() {            return ConcurrentHashMap.this.isEmpty();        }        public void clear() {            ConcurrentHashMap.this.clear();        }    }    /* ---------------- Serialization Support -------------- */    /**     * Save the state of the <tt>ConcurrentHashMap</tt> instance to a     * stream (i.e., serialize it).     * @param s the stream     * @serialData     * 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 {        // force all segments for serialization compatibility        for (int k = 0; k < segments.length; ++k)            ensureSegment(k);        s.defaultWriteObject();        final Segment<K,V>[] segments = this.segments;        for (int k = 0; k < segments.length; ++k) {            Segment<K,V> seg = segmentAt(segments, k);            seg.lock();            try {                HashEntry<K,V>[] tab = seg.table;                for (int i = 0; i < tab.length; ++i) {                    HashEntry<K,V> e;                    for (e = entryAt(tab, i); e != null; e = e.next) {                        s.writeObject(e.key);                        s.writeObject(e.value);                    }                }            } finally {                seg.unlock();            }        }        s.writeObject(null);        s.writeObject(null);    }    /**     * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a     * stream (i.e., deserialize it).     * @param s the stream     */    @SuppressWarnings("unchecked")    private void readObject(java.io.ObjectInputStream s)        throws IOException, ClassNotFoundException {        // Don't call defaultReadObject()        ObjectInputStream.GetField oisFields = s.readFields();        final Segment<K,V>[] oisSegments = (Segment<K,V>[])oisFields.get("segments", null);        final int ssize = oisSegments.length;        if (ssize < 1 || ssize > MAX_SEGMENTS            || (ssize & (ssize-1)) != 0 )  // ssize not power of two            throw new java.io.InvalidObjectException("Bad number of segments:"                                                     + ssize);        int sshift = 0, ssizeTmp = ssize;        while (ssizeTmp > 1) {            ++sshift;            ssizeTmp >>>= 1;        }        UNSAFE.putIntVolatile(this, SEGSHIFT_OFFSET, 32 - sshift);        UNSAFE.putIntVolatile(this, SEGMASK_OFFSET, ssize - 1);        UNSAFE.putObjectVolatile(this, SEGMENTS_OFFSET, oisSegments);        // set hashMask        UNSAFE.putIntVolatile(this, HASHSEED_OFFSET, randomHashSeed(this));        // Re-initialize segments to be minimally sized, and let grow.        int cap = MIN_SEGMENT_TABLE_CAPACITY;        final Segment<K,V>[] segments = this.segments;        for (int k = 0; k < segments.length; ++k) {            Segment<K,V> seg = segments[k];            if (seg != null) {                seg.threshold = (int)(cap * seg.loadFactor);                seg.table = (HashEntry<K,V>[]) new HashEntry[cap];            }        }        // Read the keys and values, and put the mappings in the table        for (;;) {            K key = (K) s.readObject();            V value = (V) s.readObject();            if (key == null)                break;            put(key, value);        }    }    // Unsafe mechanics    private static final sun.misc.Unsafe UNSAFE;    private static final long SBASE;    private static final int SSHIFT;    private static final long TBASE;    private static final int TSHIFT;    private static final long HASHSEED_OFFSET;    private static final long SEGSHIFT_OFFSET;    private static final long SEGMASK_OFFSET;    private static final long SEGMENTS_OFFSET;    static {        int ss, ts;        try {            UNSAFE = sun.misc.Unsafe.getUnsafe();            Class tc = HashEntry[].class;            Class sc = Segment[].class;            TBASE = UNSAFE.arrayBaseOffset(tc);            SBASE = UNSAFE.arrayBaseOffset(sc);            ts = UNSAFE.arrayIndexScale(tc);            ss = UNSAFE.arrayIndexScale(sc);            HASHSEED_OFFSET = UNSAFE.objectFieldOffset(                ConcurrentHashMap.class.getDeclaredField("hashSeed"));            SEGSHIFT_OFFSET = UNSAFE.objectFieldOffset(                ConcurrentHashMap.class.getDeclaredField("segmentShift"));            SEGMASK_OFFSET = UNSAFE.objectFieldOffset(                ConcurrentHashMap.class.getDeclaredField("segmentMask"));            SEGMENTS_OFFSET = UNSAFE.objectFieldOffset(                ConcurrentHashMap.class.getDeclaredField("segments"));        } catch (Exception e) {            throw new Error(e);        }        if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)            throw new Error("data type scale not a power of two");        SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);        TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);    }}

CopyOnWriteArrayList

CopyOnWriteArrayList是同步List的并发替代品,它提供了更好的并发性,并避免了在迭代期间加锁和复制。

List实现类CopyOnWriteArrayList:

package java.util.concurrent;import java.util.*;import java.util.concurrent.locks.*;import sun.misc.Unsafe;/** * A thread-safe variant of {@link java.util.ArrayList} in which all mutative * operations (<tt>add</tt>, <tt>set</tt>, and so on) are implemented by * making a fresh copy of the underlying array. * * <p> This is ordinarily too costly, but may be <em>more</em> efficient * than alternatives when traversal operations vastly outnumber * mutations, and is useful when you cannot or don't want to * synchronize traversals, yet need to preclude interference among * concurrent threads.  The "snapshot" style iterator method uses a * reference to the state of the array at the point that the iterator * was created. This array never changes during the lifetime of the * iterator, so interference is impossible and the iterator is * guaranteed not to throw <tt>ConcurrentModificationException</tt>. * The iterator will not reflect additions, removals, or changes to * the list since the iterator was created.  Element-changing * operations on iterators themselves (<tt>remove</tt>, <tt>set</tt>, and * <tt>add</tt>) are not supported. These methods throw * <tt>UnsupportedOperationException</tt>. * * <p>All elements are permitted, including <tt>null</tt>. * * <p>Memory consistency effects: As with other concurrent * collections, actions in a thread prior to placing an object into a * {@code CopyOnWriteArrayList} * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> * actions subsequent to the access or removal of that element from * the {@code CopyOnWriteArrayList} in another thread. * * <p>This class is a member of the * <a href="{@docRoot}/../technotes/guides/collections/index.html"> * Java Collections Framework</a>. * * @since 1.5 * @author Doug Lea * @param <E> the type of elements held in this collection */public class CopyOnWriteArrayList<E>    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {    private static final long serialVersionUID = 8673264195747942595L;    /** The lock protecting all mutators */    transient final ReentrantLock lock = new ReentrantLock();    /** The array, accessed only via getArray/setArray. */    private volatile transient Object[] array;    /**     * Gets the array.  Non-private so as to also be accessible     * from CopyOnWriteArraySet class.     */    final Object[] getArray() {        return array;    }    /**     * Sets the array.     */    final void setArray(Object[] a) {        array = a;    }    /**     * Creates an empty list.     */    public CopyOnWriteArrayList() {        setArray(new Object[0]);    }    /**     * Creates a list containing the elements of the specified     * collection, in the order they are returned by the collection's     * iterator.     *     * @param c the collection of initially held elements     * @throws NullPointerException if the specified collection is null     */    public CopyOnWriteArrayList(Collection<? extends E> c) {        Object[] elements = c.toArray();        // c.toArray might (incorrectly) not return Object[] (see 6260652)        if (elements.getClass() != Object[].class)            elements = Arrays.copyOf(elements, elements.length, Object[].class);        setArray(elements);    }    /**     * Creates a list holding a copy of the given array.     *     * @param toCopyIn the array (a copy of this array is used as the     *        internal array)     * @throws NullPointerException if the specified array is null     */    public CopyOnWriteArrayList(E[] toCopyIn) {        setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));    }    /**     * Returns the number of elements in this list.     *     * @return the number of elements in this list     */    public int size() {        return getArray().length;    }    /**     * Returns <tt>true</tt> if this list contains no elements.     *     * @return <tt>true</tt> if this list contains no elements     */    public boolean isEmpty() {        return size() == 0;    }    /**     * Test for equality, coping with nulls.     */    private static boolean eq(Object o1, Object o2) {        return (o1 == null ? o2 == null : o1.equals(o2));    }    /**     * static version of indexOf, to allow repeated calls without     * needing to re-acquire array each time.     * @param o element to search for     * @param elements the array     * @param index first index to search     * @param fence one past last index to search     * @return index of element, or -1 if absent     */    private static int indexOf(Object o, Object[] elements,                               int index, int fence) {        if (o == null) {            for (int i = index; i < fence; i++)                if (elements[i] == null)                    return i;        } else {            for (int i = index; i < fence; i++)                if (o.equals(elements[i]))                    return i;        }        return -1;    }    /**     * static version of lastIndexOf.     * @param o element to search for     * @param elements the array     * @param index first index to search     * @return index of element, or -1 if absent     */    private static int lastIndexOf(Object o, Object[] elements, int index) {        if (o == null) {            for (int i = index; i >= 0; i--)                if (elements[i] == null)                    return i;        } else {            for (int i = index; i >= 0; i--)                if (o.equals(elements[i]))                    return i;        }        return -1;    }    /**     * Returns <tt>true</tt> if this list contains the specified element.     * More formally, returns <tt>true</tt> if and only if this list contains     * at least one element <tt>e</tt> such that     * <tt>(o==null ? e==null : o.equals(e))</tt>.     *     * @param o element whose presence in this list is to be tested     * @return <tt>true</tt> if this list contains the specified element     */    public boolean contains(Object o) {        Object[] elements = getArray();        return indexOf(o, elements, 0, elements.length) >= 0;    }    /**     * {@inheritDoc}     */    public int indexOf(Object o) {        Object[] elements = getArray();        return indexOf(o, elements, 0, elements.length);    }    /**     * Returns the index of the first occurrence of the specified element in     * this list, searching forwards from <tt>index</tt>, or returns -1 if     * the element is not found.     * More formally, returns the lowest index <tt>i</tt> such that     * <tt>(i >= index && (e==null ? get(i)==null : e.equals(get(i))))</tt>,     * or -1 if there is no such index.     *     * @param e element to search for     * @param index index to start searching from     * @return the index of the first occurrence of the element in     *         this list at position <tt>index</tt> or later in the list;     *         <tt>-1</tt> if the element is not found.     * @throws IndexOutOfBoundsException if the specified index is negative     */    public int indexOf(E e, int index) {        Object[] elements = getArray();        return indexOf(e, elements, index, elements.length);    }    /**     * {@inheritDoc}     */    public int lastIndexOf(Object o) {        Object[] elements = getArray();        return lastIndexOf(o, elements, elements.length - 1);    }    /**     * Returns the index of the last occurrence of the specified element in     * this list, searching backwards from <tt>index</tt>, or returns -1 if     * the element is not found.     * More formally, returns the highest index <tt>i</tt> such that     * <tt>(i <= index && (e==null ? get(i)==null : e.equals(get(i))))</tt>,     * or -1 if there is no such index.     *     * @param e element to search for     * @param index index to start searching backwards from     * @return the index of the last occurrence of the element at position     *         less than or equal to <tt>index</tt> in this list;     *         -1 if the element is not found.     * @throws IndexOutOfBoundsException if the specified index is greater     *         than or equal to the current size of this list     */    public int lastIndexOf(E e, int index) {        Object[] elements = getArray();        return lastIndexOf(e, elements, index);    }    /**     * Returns a shallow copy of this list.  (The elements themselves     * are not copied.)     *     * @return a clone of this list     */    public Object clone() {        try {            CopyOnWriteArrayList c = (CopyOnWriteArrayList)(super.clone());            c.resetLock();            return c;        } catch (CloneNotSupportedException e) {            // this shouldn't happen, since we are Cloneable            throw new InternalError();        }    }    /**     * Returns an array containing all of the elements in this list     * in proper sequence (from first to last element).     *     * <p>The returned array will be "safe" in that no references to it are     * maintained by this list.  (In other words, this method must allocate     * a new array).  The caller is thus free to modify the returned array.     *     * <p>This method acts as bridge between array-based and collection-based     * APIs.     *     * @return an array containing all the elements in this list     */    public Object[] toArray() {        Object[] elements = getArray();        return Arrays.copyOf(elements, elements.length);    }    /**     * Returns an array containing all of the elements in this list in     * proper sequence (from first to last element); the runtime type of     * the returned array is that of the specified array.  If the list fits     * in the specified array, it is returned therein.  Otherwise, a new     * array is allocated with the runtime type of the specified array and     * the size of this list.     *     * <p>If this list fits in the specified array with room to spare     * (i.e., the array has more elements than this list), the element in     * the array immediately following the end of the list is set to     * <tt>null</tt>.  (This is useful in determining the length of this     * list <i>only</i> if the caller knows that this list does not contain     * any null elements.)     *     * <p>Like the {@link #toArray()} method, this method acts as bridge between     * array-based and collection-based APIs.  Further, this method allows     * precise control over the runtime type of the output array, and may,     * under certain circumstances, be used to save allocation costs.     *     * <p>Suppose <tt>x</tt> is a list known to contain only strings.     * The following code can be used to dump the list into a newly     * allocated array of <tt>String</tt>:     *     * <pre>     *     String[] y = x.toArray(new String[0]);</pre>     *     * Note that <tt>toArray(new Object[0])</tt> is identical in function to     * <tt>toArray()</tt>.     *     * @param a the array into which the elements of the list are to     *          be stored, if it is big enough; otherwise, a new array of the     *          same runtime type is allocated for this purpose.     * @return an array containing all the elements in this list     * @throws ArrayStoreException if the runtime type of the specified array     *         is not a supertype of the runtime type of every element in     *         this list     * @throws NullPointerException if the specified array is null     */    @SuppressWarnings("unchecked")    public <T> T[] toArray(T a[]) {        Object[] elements = getArray();        int len = elements.length;        if (a.length < len)            return (T[]) Arrays.copyOf(elements, len, a.getClass());        else {            System.arraycopy(elements, 0, a, 0, len);            if (a.length > len)                a[len] = null;            return a;        }    }    // Positional Access Operations    @SuppressWarnings("unchecked")    private E get(Object[] a, int index) {        return (E) a[index];    }    /**     * {@inheritDoc}     *     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public E get(int index) {        return get(getArray(), index);    }    /**     * Replaces the element at the specified position in this list with the     * specified element.     *     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public E set(int index, E element) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            E oldValue = get(elements, index);            if (oldValue != element) {                int len = elements.length;                Object[] newElements = Arrays.copyOf(elements, len);                newElements[index] = element;                setArray(newElements);            } else {                // Not quite a no-op; ensures volatile write semantics                setArray(elements);            }            return oldValue;        } finally {            lock.unlock();        }    }    /**     * Appends the specified element to the end of this list.     *     * @param e element to be appended to this list     * @return <tt>true</tt> (as specified by {@link Collection#add})     */    public boolean add(E e) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            Object[] newElements = Arrays.copyOf(elements, len + 1);            newElements[len] = e;            setArray(newElements);            return true;        } finally {            lock.unlock();        }    }    /**     * Inserts the specified element at the specified position in this     * list. Shifts the element currently at that position (if any) and     * any subsequent elements to the right (adds one to their indices).     *     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public void add(int index, E element) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            if (index > len || index < 0)                throw new IndexOutOfBoundsException("Index: "+index+                                                    ", Size: "+len);            Object[] newElements;            int numMoved = len - index;            if (numMoved == 0)                newElements = Arrays.copyOf(elements, len + 1);            else {                newElements = new Object[len + 1];                System.arraycopy(elements, 0, newElements, 0, index);                System.arraycopy(elements, index, newElements, index + 1,                                 numMoved);            }            newElements[index] = element;            setArray(newElements);        } finally {            lock.unlock();        }    }    /**     * Removes the element at the specified position in this list.     * Shifts any subsequent elements to the left (subtracts one from their     * indices).  Returns the element that was removed from the list.     *     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public E remove(int index) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            E oldValue = get(elements, index);            int numMoved = len - index - 1;            if (numMoved == 0)                setArray(Arrays.copyOf(elements, len - 1));            else {                Object[] newElements = new Object[len - 1];                System.arraycopy(elements, 0, newElements, 0, index);                System.arraycopy(elements, index + 1, newElements, index,                                 numMoved);                setArray(newElements);            }            return oldValue;        } finally {            lock.unlock();        }    }    /**     * Removes the first occurrence of the specified element from this list,     * if it is present.  If this list does not contain the element, it is     * unchanged.  More formally, removes the element with the lowest index     * <tt>i</tt> such that     * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>     * (if such an element exists).  Returns <tt>true</tt> if this list     * contained the specified element (or equivalently, if this list     * changed as a result of the call).     *     * @param o element to be removed from this list, if present     * @return <tt>true</tt> if this list contained the specified element     */    public boolean remove(Object o) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            if (len != 0) {                // Copy while searching for element to remove                // This wins in the normal case of element being present                int newlen = len - 1;                Object[] newElements = new Object[newlen];                for (int i = 0; i < newlen; ++i) {                    if (eq(o, elements[i])) {                        // found one;  copy remaining and exit                        for (int k = i + 1; k < len; ++k)                            newElements[k-1] = elements[k];                        setArray(newElements);                        return true;                    } else                        newElements[i] = elements[i];                }                // special handling for last cell                if (eq(o, elements[newlen])) {                    setArray(newElements);                    return true;                }            }            return false;        } finally {            lock.unlock();        }    }    /**     * Removes from this list all of the elements whose index is between     * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.     * Shifts any succeeding elements to the left (reduces their index).     * This call shortens the list by <tt>(toIndex - fromIndex)</tt> elements.     * (If <tt>toIndex==fromIndex</tt>, this operation has no effect.)     *     * @param fromIndex index of first element to be removed     * @param toIndex index after last element to be removed     * @throws IndexOutOfBoundsException if fromIndex or toIndex out of range     *         ({@code{fromIndex < 0 || toIndex > size() || toIndex < fromIndex})     */    private void removeRange(int fromIndex, int toIndex) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)                throw new IndexOutOfBoundsException();            int newlen = len - (toIndex - fromIndex);            int numMoved = len - toIndex;            if (numMoved == 0)                setArray(Arrays.copyOf(elements, newlen));            else {                Object[] newElements = new Object[newlen];                System.arraycopy(elements, 0, newElements, 0, fromIndex);                System.arraycopy(elements, toIndex, newElements,                                 fromIndex, numMoved);                setArray(newElements);            }        } finally {            lock.unlock();        }    }    /**     * Append the element if not present.     *     * @param e element to be added to this list, if absent     * @return <tt>true</tt> if the element was added     */    public boolean addIfAbsent(E e) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            // Copy while checking if already present.            // This wins in the most common case where it is not present            Object[] elements = getArray();            int len = elements.length;            Object[] newElements = new Object[len + 1];            for (int i = 0; i < len; ++i) {                if (eq(e, elements[i]))                    return false; // exit, throwing away copy                else                    newElements[i] = elements[i];            }            newElements[len] = e;            setArray(newElements);            return true;        } finally {            lock.unlock();        }    }    /**     * Returns <tt>true</tt> if this list contains all of the elements of the     * specified collection.     *     * @param c collection to be checked for containment in this list     * @return <tt>true</tt> if this list contains all of the elements of the     *         specified collection     * @throws NullPointerException if the specified collection is null     * @see #contains(Object)     */    public boolean containsAll(Collection<?> c) {        Object[] elements = getArray();        int len = elements.length;        for (Object e : c) {            if (indexOf(e, elements, 0, len) < 0)                return false;        }        return true;    }    /**     * Removes from this list all of its elements that are contained in     * the specified collection. This is a particularly expensive operation     * in this class because of the need for an internal temporary array.     *     * @param c collection containing elements to be removed from this list     * @return <tt>true</tt> if this list changed as a result of the call     * @throws ClassCastException if the class of an element of this list     *         is incompatible with the specified collection     *         (<a href="../Collection.html#optional-restrictions">optional</a>)     * @throws NullPointerException if this list contains a null element and the     *         specified collection does not permit null elements     *         (<a href="../Collection.html#optional-restrictions">optional</a>),     *         or if the specified collection is null     * @see #remove(Object)     */    public boolean removeAll(Collection<?> c) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            if (len != 0) {                // temp array holds those elements we know we want to keep                int newlen = 0;                Object[] temp = new Object[len];                for (int i = 0; i < len; ++i) {                    Object element = elements[i];                    if (!c.contains(element))                        temp[newlen++] = element;                }                if (newlen != len) {                    setArray(Arrays.copyOf(temp, newlen));                    return true;                }            }            return false;        } finally {            lock.unlock();        }    }    /**     * Retains only the elements in this list that are contained in the     * specified collection.  In other words, removes from this list all of     * its elements that are not contained in the specified collection.     *     * @param c collection containing elements to be retained in this list     * @return <tt>true</tt> if this list changed as a result of the call     * @throws ClassCastException if the class of an element of this list     *         is incompatible with the specified collection     *         (<a href="../Collection.html#optional-restrictions">optional</a>)     * @throws NullPointerException if this list contains a null element and the     *         specified collection does not permit null elements     *         (<a href="../Collection.html#optional-restrictions">optional</a>),     *         or if the specified collection is null     * @see #remove(Object)     */    public boolean retainAll(Collection<?> c) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            if (len != 0) {                // temp array holds those elements we know we want to keep                int newlen = 0;                Object[] temp = new Object[len];                for (int i = 0; i < len; ++i) {                    Object element = elements[i];                    if (c.contains(element))                        temp[newlen++] = element;                }                if (newlen != len) {                    setArray(Arrays.copyOf(temp, newlen));                    return true;                }            }            return false;        } finally {            lock.unlock();        }    }    /**     * Appends all of the elements in the specified collection that     * are not already contained in this list, to the end of     * this list, in the order that they are returned by the     * specified collection's iterator.     *     * @param c collection containing elements to be added to this list     * @return the number of elements added     * @throws NullPointerException if the specified collection is null     * @see #addIfAbsent(Object)     */    public int addAllAbsent(Collection<? extends E> c) {        Object[] cs = c.toArray();        if (cs.length == 0)            return 0;        Object[] uniq = new Object[cs.length];        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            int added = 0;            for (int i = 0; i < cs.length; ++i) { // scan for duplicates                Object e = cs[i];                if (indexOf(e, elements, 0, len) < 0 &&                    indexOf(e, uniq, 0, added) < 0)                    uniq[added++] = e;            }            if (added > 0) {                Object[] newElements = Arrays.copyOf(elements, len + added);                System.arraycopy(uniq, 0, newElements, len, added);                setArray(newElements);            }            return added;        } finally {            lock.unlock();        }    }    /**     * Removes all of the elements from this list.     * The list will be empty after this call returns.     */    public void clear() {        final ReentrantLock lock = this.lock;        lock.lock();        try {            setArray(new Object[0]);        } finally {            lock.unlock();        }    }    /**     * Appends all of the elements in the specified collection to the end     * of this list, in the order that they are returned by the specified     * collection's iterator.     *     * @param c collection containing elements to be added to this list     * @return <tt>true</tt> if this list changed as a result of the call     * @throws NullPointerException if the specified collection is null     * @see #add(Object)     */    public boolean addAll(Collection<? extends E> c) {        Object[] cs = c.toArray();        if (cs.length == 0)            return false;        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            Object[] newElements = Arrays.copyOf(elements, len + cs.length);            System.arraycopy(cs, 0, newElements, len, cs.length);            setArray(newElements);            return true;        } finally {            lock.unlock();        }    }    /**     * Inserts all of the elements in the specified collection into this     * list, starting at the specified position.  Shifts the element     * currently at that position (if any) and any subsequent elements to     * the right (increases their indices).  The new elements will appear     * in this list in the order that they are returned by the     * specified collection's iterator.     *     * @param index index at which to insert the first element     *        from the specified collection     * @param c collection containing elements to be added to this list     * @return <tt>true</tt> if this list changed as a result of the call     * @throws IndexOutOfBoundsException {@inheritDoc}     * @throws NullPointerException if the specified collection is null     * @see #add(int,Object)     */    public boolean addAll(int index, Collection<? extends E> c) {        Object[] cs = c.toArray();        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            if (index > len || index < 0)                throw new IndexOutOfBoundsException("Index: "+index+                                                    ", Size: "+len);            if (cs.length == 0)                return false;            int numMoved = len - index;            Object[] newElements;            if (numMoved == 0)                newElements = Arrays.copyOf(elements, len + cs.length);            else {                newElements = new Object[len + cs.length];                System.arraycopy(elements, 0, newElements, 0, index);                System.arraycopy(elements, index,                                 newElements, index + cs.length,                                 numMoved);            }            System.arraycopy(cs, 0, newElements, index, cs.length);            setArray(newElements);            return true;        } finally {            lock.unlock();        }    }    /**     * Saves the state of the list to a stream (that is, serializes it).     *     * @serialData The length of the array backing the list is emitted     *               (int), followed by all of its elements (each an Object)     *               in the proper order.     * @param s the stream     */    private void writeObject(java.io.ObjectOutputStream s)        throws java.io.IOException{        s.defaultWriteObject();        Object[] elements = getArray();        // Write out array length        s.writeInt(elements.length);        // Write out all elements in the proper order.        for (Object element : elements)            s.writeObject(element);    }    /**     * Reconstitutes the list from a stream (that is, deserializes it).     *     * @param s the stream     */    private void readObject(java.io.ObjectInputStream s)        throws java.io.IOException, ClassNotFoundException {        s.defaultReadObject();        // bind to new lock        resetLock();        // Read in array length and allocate array        int len = s.readInt();        Object[] elements = new Object[len];        // Read in all elements in the proper order.        for (int i = 0; i < len; i++)            elements[i] = s.readObject();        setArray(elements);    }    /**     * Returns a string representation of this list.  The string     * representation consists of the string representations of the list's     * elements in the order they are returned by its iterator, enclosed in     * square brackets (<tt>"[]"</tt>).  Adjacent elements are separated by     * the characters <tt>", "</tt> (comma and space).  Elements are     * converted to strings as by {@link String#valueOf(Object)}.     *     * @return a string representation of this list     */    public String toString() {        return Arrays.toString(getArray());    }    /**     * Compares the specified object with this list for equality.     * Returns {@code true} if the specified object is the same object     * as this object, or if it is also a {@link List} and the sequence     * of elements returned by an {@linkplain List#iterator() iterator}     * over the specified list is the same as the sequence returned by     * an iterator over this list.  The two sequences are considered to     * be the same if they have the same length and corresponding     * elements at the same position in the sequence are <em>equal</em>.     * Two elements {@code e1} and {@code e2} are considered     * <em>equal</em> if {@code (e1==null ? e2==null : e1.equals(e2))}.     *     * @param o the object to be compared for equality with this list     * @return {@code true} if the specified object is equal to this list     */    public boolean equals(Object o) {        if (o == this)            return true;        if (!(o instanceof List))            return false;        List<?> list = (List<?>)(o);        Iterator<?> it = list.iterator();        Object[] elements = getArray();        int len = elements.length;        for (int i = 0; i < len; ++i)            if (!it.hasNext() || !eq(elements[i], it.next()))                return false;        if (it.hasNext())            return false;        return true;    }    /**     * Returns the hash code value for this list.     *     * <p>This implementation uses the definition in {@link List#hashCode}.     *     * @return the hash code value for this list     */    public int hashCode() {        int hashCode = 1;        Object[] elements = getArray();        int len = elements.length;        for (int i = 0; i < len; ++i) {            Object obj = elements[i];            hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());        }        return hashCode;    }    /**     * Returns an iterator over the elements in this list in proper sequence.     *     * <p>The returned iterator provides a snapshot of the state of the list     * when the iterator was constructed. No synchronization is needed while     * traversing the iterator. The iterator does <em>NOT</em> support the     * <tt>remove</tt> method.     *     * @return an iterator over the elements in this list in proper sequence     */    public Iterator<E> iterator() {        return new COWIterator<E>(getArray(), 0);    }    /**     * {@inheritDoc}     *     * <p>The returned iterator provides a snapshot of the state of the list     * when the iterator was constructed. No synchronization is needed while     * traversing the iterator. The iterator does <em>NOT</em> support the     * <tt>remove</tt>, <tt>set</tt> or <tt>add</tt> methods.     */    public ListIterator<E> listIterator() {        return new COWIterator<E>(getArray(), 0);    }    /**     * {@inheritDoc}     *     * <p>The returned iterator provides a snapshot of the state of the list     * when the iterator was constructed. No synchronization is needed while     * traversing the iterator. The iterator does <em>NOT</em> support the     * <tt>remove</tt>, <tt>set</tt> or <tt>add</tt> methods.     *     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public ListIterator<E> listIterator(final int index) {        Object[] elements = getArray();        int len = elements.length;        if (index<0 || index>len)            throw new IndexOutOfBoundsException("Index: "+index);        return new COWIterator<E>(elements, index);    }    private static class COWIterator<E> implements ListIterator<E> {        /** Snapshot of the array */        private final Object[] snapshot;        /** Index of element to be returned by subsequent call to next.  */        private int cursor;        private COWIterator(Object[] elements, int initialCursor) {            cursor = initialCursor;            snapshot = elements;        }        public boolean hasNext() {            return cursor < snapshot.length;        }        public boolean hasPrevious() {            return cursor > 0;        }        @SuppressWarnings("unchecked")        public E next() {            if (! hasNext())                throw new NoSuchElementException();            return (E) snapshot[cursor++];        }        @SuppressWarnings("unchecked")        public E previous() {            if (! hasPrevious())                throw new NoSuchElementException();            return (E) snapshot[--cursor];        }        public int nextIndex() {            return cursor;        }        public int previousIndex() {            return cursor-1;        }        /**         * Not supported. Always throws UnsupportedOperationException.         * @throws UnsupportedOperationException always; <tt>remove</tt>         *         is not supported by this iterator.         */        public void remove() {            throw new UnsupportedOperationException();        }        /**         * Not supported. Always throws UnsupportedOperationException.         * @throws UnsupportedOperationException always; <tt>set</tt>         *         is not supported by this iterator.         */        public void set(E e) {            throw new UnsupportedOperationException();        }        /**         * Not supported. Always throws UnsupportedOperationException.         * @throws UnsupportedOperationException always; <tt>add</tt>         *         is not supported by this iterator.         */        public void add(E e) {            throw new UnsupportedOperationException();        }    }    /**     * Returns a view of the portion of this list between     * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.     * The returned list is backed by this list, so changes in the     * returned list are reflected in this list.     *     * <p>The semantics of the list returned by this method become     * undefined if the backing list (i.e., this list) is modified in     * any way other than via the returned list.     *     * @param fromIndex low endpoint (inclusive) of the subList     * @param toIndex high endpoint (exclusive) of the subList     * @return a view of the specified range within this list     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public List<E> subList(int fromIndex, int toIndex) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)                throw new IndexOutOfBoundsException();            return new COWSubList<E>(this, fromIndex, toIndex);        } finally {            lock.unlock();        }    }    /**     * Sublist for CopyOnWriteArrayList.     * This class extends AbstractList merely for convenience, to     * avoid having to define addAll, etc. This doesn't hurt, but     * is wasteful.  This class does not need or use modCount     * mechanics in AbstractList, but does need to check for     * concurrent modification using similar mechanics.  On each     * operation, the array that we expect the backing list to use     * is checked and updated.  Since we do this for all of the     * base operations invoked by those defined in AbstractList,     * all is well.  While inefficient, this is not worth     * improving.  The kinds of list operations inherited from     * AbstractList are already so slow on COW sublists that     * adding a bit more space/time doesn't seem even noticeable.     */    private static class COWSubList<E>        extends AbstractList<E>        implements RandomAccess    {        private final CopyOnWriteArrayList<E> l;        private final int offset;        private int size;        private Object[] expectedArray;        // only call this holding l's lock        COWSubList(CopyOnWriteArrayList<E> list,                   int fromIndex, int toIndex) {            l = list;            expectedArray = l.getArray();            offset = fromIndex;            size = toIndex - fromIndex;        }        // only call this holding l's lock        private void checkForComodification() {            if (l.getArray() != expectedArray)                throw new ConcurrentModificationException();        }        // only call this holding l's lock        private void rangeCheck(int index) {            if (index<0 || index>=size)                throw new IndexOutOfBoundsException("Index: "+index+                                                    ",Size: "+size);        }        public E set(int index, E element) {            final ReentrantLock lock = l.lock;            lock.lock();            try {                rangeCheck(index);                checkForComodification();                E x = l.set(index+offset, element);                expectedArray = l.getArray();                return x;            } finally {                lock.unlock();            }        }        public E get(int index) {            final ReentrantLock lock = l.lock;            lock.lock();            try {                rangeCheck(index);                checkForComodification();                return l.get(index+offset);            } finally {                lock.unlock();            }        }        public int size() {            final ReentrantLock lock = l.lock;            lock.lock();            try {                checkForComodification();                return size;            } finally {                lock.unlock();            }        }        public void add(int index, E element) {            final ReentrantLock lock = l.lock;            lock.lock();            try {                checkForComodification();                if (index<0 || index>size)                    throw new IndexOutOfBoundsException();                l.add(index+offset, element);                expectedArray = l.getArray();                size++;            } finally {                lock.unlock();            }        }        public void clear() {            final ReentrantLock lock = l.lock;            lock.lock();            try {                checkForComodification();                l.removeRange(offset, offset+size);                expectedArray = l.getArray();                size = 0;            } finally {                lock.unlock();            }        }        public E remove(int index) {            final ReentrantLock lock = l.lock;            lock.lock();            try {                rangeCheck(index);                checkForComodification();                E result = l.remove(index+offset);                expectedArray = l.getArray();                size--;                return result;            } finally {                lock.unlock();            }        }        public boolean remove(Object o) {            int index = indexOf(o);            if (index == -1)                return false;            remove(index);            return true;        }        public Iterator<E> iterator() {            final ReentrantLock lock = l.lock;            lock.lock();            try {                checkForComodification();                return new COWSubListIterator<E>(l, 0, offset, size);            } finally {                lock.unlock();            }        }        public ListIterator<E> listIterator(final int index) {            final ReentrantLock lock = l.lock;            lock.lock();            try {                checkForComodification();                if (index<0 || index>size)                    throw new IndexOutOfBoundsException("Index: "+index+                                                        ", Size: "+size);                return new COWSubListIterator<E>(l, index, offset, size);            } finally {                lock.unlock();            }        }        public List<E> subList(int fromIndex, int toIndex) {            final ReentrantLock lock = l.lock;            lock.lock();            try {                checkForComodification();                if (fromIndex<0 || toIndex>size)                    throw new IndexOutOfBoundsException();                return new COWSubList<E>(l, fromIndex + offset,                                         toIndex + offset);            } finally {                lock.unlock();            }        }    }    private static class COWSubListIterator<E> implements ListIterator<E> {        private final ListIterator<E> i;        private final int index;        private final int offset;        private final int size;        COWSubListIterator(List<E> l, int index, int offset,                           int size) {            this.index = index;            this.offset = offset;            this.size = size;            i = l.listIterator(index+offset);        }        public boolean hasNext() {            return nextIndex() < size;        }        public E next() {            if (hasNext())                return i.next();            else                throw new NoSuchElementException();        }        public boolean hasPrevious() {            return previousIndex() >= 0;        }        public E previous() {            if (hasPrevious())                return i.previous();            else                throw new NoSuchElementException();        }        public int nextIndex() {            return i.nextIndex() - offset;        }        public int previousIndex() {            return i.previousIndex() - offset;        }        public void remove() {            throw new UnsupportedOperationException();        }        public void set(E e) {            throw new UnsupportedOperationException();        }        public void add(E e) {            throw new UnsupportedOperationException();        }    }    // Support for resetting lock while deserializing    private void resetLock() {        UNSAFE.putObjectVolatile(this, lockOffset, new ReentrantLock());    }    private static final sun.misc.Unsafe UNSAFE;    private static final long lockOffset;    static {        try {            UNSAFE = sun.misc.Unsafe.getUnsafe();            Class k = CopyOnWriteArrayList.class;            lockOffset = UNSAFE.objectFieldOffset                (k.getDeclaredField("lock"));        } catch (Exception e) {            throw new Error(e);        }    }}



0 0