From 68b7d273d2b7d60969da6e18eb92d876d376f81f Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 17 Jul 2013 15:32:11 +0400 Subject: [PATCH] reformat --- .../util/containers/ConcurrentHashMap.java | 2334 ++++++++--------- 1 file changed, 1167 insertions(+), 1167 deletions(-) diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java index ca366a24b524..4e74afac314e 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java @@ -30,7 +30,7 @@ import java.util.concurrent.locks.ReentrantLock; // added cacheOrGet convenience method // changed DEFAULT_SEGMENTS to 2 from 16 public class ConcurrentHashMap extends AbstractMap implements ConcurrentMap, Serializable, TObjectHashingStrategy { - private static final long serialVersionUID = 7249069246763182397L; + private static final long serialVersionUID = 7249069246763182397L; /* * The basic strategy is to subdivide the table among Segments, @@ -39,113 +39,113 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /* ---------------- Constants -------------- */ - /** - * The default initial number of table slots for this table. - * Used when not otherwise specified in constructor. - */ - static int DEFAULT_INITIAL_CAPACITY = 16; + /** + * The default initial number of table slots for this table. + * Used when not otherwise specified in constructor. + */ + static int DEFAULT_INITIAL_CAPACITY = 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 indexible - * using ints. - */ - static final int MAXIMUM_CAPACITY = 1 << 30; + /** + * 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 indexible + * using ints. + */ + static final int MAXIMUM_CAPACITY = 1 << 30; - /** - * The default load factor for this table. Used when not - * otherwise specified in constructor. - */ - public static final float DEFAULT_LOAD_FACTOR = 0.75f; + /** + * The default load factor for this table. Used when not + * otherwise specified in constructor. + */ + public static final float DEFAULT_LOAD_FACTOR = 0.75f; - /** - * The default number of concurrency control segments. - **/ - static final int DEFAULT_SEGMENTS = Math.min(2, Runtime.getRuntime().availableProcessors()); // CHANGED FROM 16 + /** + * The default number of concurrency control segments. + **/ + static final int DEFAULT_SEGMENTS = Math.min(2, Runtime.getRuntime().availableProcessors()); // CHANGED FROM 16 - /** - * The maximum number of segments to allow; used to bound - * constructor arguments. - */ - static final int MAX_SEGMENTS = 1 << 16; // slightly conservative + /** + * The maximum number of segments to allow; used to bound + * constructor arguments. + */ + 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; + /** + * 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 -------------- */ - /** - * Mask value for indexing into segments. The upper bits of a - * key's hash code are used to choose the segment. - **/ - final int segmentMask; + /** + * 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; + /** + * Shift value for indexing within segments. + **/ + final int segmentShift; - /** - * The segments, each of which is a specialized hash table - */ - final Segment[] segments; + /** + * The segments, each of which is a specialized hash table + */ + final Segment[] segments; - transient Set keySet; - transient Set> entrySet; - transient Collection values; + transient Set keySet; + transient Set> entrySet; + transient Collection values; private final TObjectHashingStrategy myHashingStrategy; /* ---------------- Small Utilities -------------- */ /** - * Returns the segment that should be used for key with given hash - * @param hash the hash code for the key - * @return the segment - */ - final Segment segmentFor(int hash) { - return segments[(hash >>> segmentShift) & segmentMask]; - } + * Returns the segment that should be used for key with given hash + * @param hash the hash code for the key + * @return the segment + */ + final Segment segmentFor(int hash) { + return segments[(hash >>> segmentShift) & segmentMask]; + } /* ---------------- Inner Classes -------------- */ - /** - * ConcurrentHashMap list entry. Note that this is never exported - * out as a user-visible Map.Entry. - * - * Because the value field is volatile, not final, it is legal wrt - * the Java Memory Model for an unsynchronized reader to see null - * instead of initial value when read via a data race. Although a - * reordering leading to this is not likely to ever actually - * occur, the Segment.readValueUnderLock method is used as a - * backup in case a null (pre-initialized) value is ever seen in - * an unsynchronized access method. - */ - static final class HashEntry { - final K key; - final int hash; - volatile V value; - final HashEntry next; + /** + * ConcurrentHashMap list entry. Note that this is never exported + * out as a user-visible Map.Entry. + * + * Because the value field is volatile, not final, it is legal wrt + * the Java Memory Model for an unsynchronized reader to see null + * instead of initial value when read via a data race. Although a + * reordering leading to this is not likely to ever actually + * occur, the Segment.readValueUnderLock method is used as a + * backup in case a null (pre-initialized) value is ever seen in + * an unsynchronized access method. + */ + static final class HashEntry { + final K key; + final int hash; + volatile V value; + final HashEntry next; - HashEntry(K key, int hash, HashEntry next, V value) { - this.key = key; - this.hash = hash; - this.next = next; - this.value = value; - } + HashEntry(K key, int hash, HashEntry next, V value) { + this.key = key; + this.hash = hash; + this.next = next; + this.value = value; } + } - /** - * 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 extends ReentrantLock implements Serializable { + /** + * 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 extends ReentrantLock implements Serializable { /* * Segments maintain a table of entry lists that are ALWAYS * kept in a consistent state, so can be read without locking. @@ -183,206 +183,206 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * count field are marked in code comments. */ - private static final long serialVersionUID = 2249069246763182397L; + private static final long serialVersionUID = 2249069246763182397L; - /** - * The number of elements in this segment's region. - **/ - transient volatile int count; + /** + * The number of elements in this segment's region. + **/ + transient volatile int count; - /** - * Number of updates that alter the size of the table. This is - * used during bulk-read methods to make sure they see a - * consistent snapshot: If modCounts change during a traversal - * of segments computing size or checking containsValue, then - * we might have an inconsistent view of state so (usually) - * must retry. - */ - transient int modCount; + /** + * Number of updates that alter the size of the table. This is + * used during bulk-read methods to make sure they see a + * consistent snapshot: If modCounts change during a traversal + * of segments computing size or checking containsValue, then + * we might have an inconsistent view of state so (usually) + * must retry. + */ + transient int modCount; - /** - * The table is rehashed when its size exceeds this threshold. - * (The value of this field is always (int)(capacity * - * loadFactor).) - */ - transient int threshold; + /** + * The table is rehashed when its size exceeds this threshold. + * (The value of this field is always (int)(capacity * + * loadFactor).) + */ + transient int threshold; - /** - * The per-segment table. Declared as a raw type, casted - * to HashEntry on each use. - */ - transient volatile HashEntry[] table; + /** + * The per-segment table. Declared as a raw type, casted + * to HashEntry on each use. + */ + transient volatile HashEntry[] table; - /** - * 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; - private final TObjectHashingStrategy myHashingStrategy; + /** + * 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; + private final TObjectHashingStrategy myHashingStrategy; - Segment(int initialCapacity, float lf, TObjectHashingStrategy hashingStrategy) { - loadFactor = lf; - myHashingStrategy = hashingStrategy; - setTable(new HashEntry[initialCapacity]); - } + Segment(int initialCapacity, float lf, TObjectHashingStrategy hashingStrategy) { + loadFactor = lf; + myHashingStrategy = hashingStrategy; + setTable(new HashEntry[initialCapacity]); + } - /** - * Set table to new HashEntry array. - * Call only while holding lock or in constructor. - **/ - void setTable(HashEntry[] newTable) { - threshold = (int)(newTable.length * loadFactor); - table = newTable; - } + /** + * Set table to new HashEntry array. + * Call only while holding lock or in constructor. + **/ + void setTable(HashEntry[] newTable) { + threshold = (int)(newTable.length * loadFactor); + table = newTable; + } - /** - * Return properly casted first entry of bin for given hash - */ - HashEntry getFirst(int hash) { - HashEntry[] tab = table; - return (HashEntry) tab[hash & (tab.length - 1)]; - } + /** + * Return properly casted first entry of bin for given hash + */ + HashEntry getFirst(int hash) { + HashEntry[] tab = table; + return (HashEntry) tab[hash & (tab.length - 1)]; + } - /** - * Read value field of an entry under lock. Called if value - * field ever appears to be null. This is possible only if a - * compiler happens to reorder a HashEntry initialization with - * its table assignment, which is legal under memory model - * but is not known to ever occur. - */ - V readValueUnderLock(HashEntry e) { - lock(); - try { - return e.value; - } finally { - unlock(); - } - } + /** + * Read value field of an entry under lock. Called if value + * field ever appears to be null. This is possible only if a + * compiler happens to reorder a HashEntry initialization with + * its table assignment, which is legal under memory model + * but is not known to ever occur. + */ + V readValueUnderLock(HashEntry e) { + lock(); + try { + return e.value; + } finally { + unlock(); + } + } /* Specialized implementations of map methods */ - V get(K key, int hash) { - if (count != 0) { // read-volatile - HashEntry e = getFirst(hash); - while (e != null) { - if (e.hash == hash && myHashingStrategy.equals(key,e.key)) { - V v = e.value; - if (v != null) - return v; - return readValueUnderLock(e); // recheck - } - e = e.next; - } - } - return null; + V get(K key, int hash) { + if (count != 0) { // read-volatile + HashEntry e = getFirst(hash); + while (e != null) { + if (e.hash == hash && myHashingStrategy.equals(key,e.key)) { + V v = e.value; + if (v != null) + return v; + return readValueUnderLock(e); // recheck + } + e = e.next; } + } + return null; + } - boolean containsKey(K key, int hash) { - if (count != 0) { // read-volatile - HashEntry e = getFirst(hash); - while (e != null) { - if (e.hash == hash && myHashingStrategy.equals(key,e.key)) - return true; - e = e.next; - } - } - return false; + boolean containsKey(K key, int hash) { + if (count != 0) { // read-volatile + HashEntry e = getFirst(hash); + while (e != null) { + if (e.hash == hash && myHashingStrategy.equals(key,e.key)) + return true; + e = e.next; } + } + return false; + } - boolean containsValue(Object value) { - if (count != 0) { // read-volatile - HashEntry[] tab = table; - int len = tab.length; - for (int i = 0 ; i < len; i++) { - for (HashEntry e = (HashEntry)tab[i]; - e != null ; - e = e.next) { - V v = e.value; - if (v == null) // recheck - v = readValueUnderLock(e); - if (value.equals(v)) - return true; - } - } - } - return false; + boolean containsValue(Object value) { + if (count != 0) { // read-volatile + HashEntry[] tab = table; + int len = tab.length; + for (int i = 0 ; i < len; i++) { + for (HashEntry e = (HashEntry)tab[i]; + e != null ; + e = e.next) { + V v = e.value; + if (v == null) // recheck + v = readValueUnderLock(e); + if (value.equals(v)) + return true; + } } + } + return false; + } - boolean replace(K key, int hash, V oldValue, V newValue) { - lock(); - try { - HashEntry e = getFirst(hash); - while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) - e = e.next; + boolean replace(K key, int hash, V oldValue, V newValue) { + lock(); + try { + HashEntry e = getFirst(hash); + while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) + e = e.next; - boolean replaced = false; - if (e != null && oldValue.equals(e.value)) { - replaced = true; - e.value = newValue; - } - return replaced; - } finally { - unlock(); - } + boolean replaced = false; + if (e != null && oldValue.equals(e.value)) { + replaced = true; + e.value = newValue; } + return replaced; + } finally { + unlock(); + } + } - V replace(K key, int hash, V newValue) { - lock(); - try { - HashEntry e = getFirst(hash); - while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) - e = e.next; + V replace(K key, int hash, V newValue) { + lock(); + try { + HashEntry e = getFirst(hash); + while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) + e = e.next; - V oldValue = null; - if (e != null) { - oldValue = e.value; - e.value = newValue; - } - return oldValue; - } finally { - unlock(); - } + V oldValue = null; + if (e != null) { + oldValue = e.value; + e.value = newValue; } + return oldValue; + } finally { + unlock(); + } + } - V put(K key, int hash, V value, boolean onlyIfAbsent) { - lock(); - try { - int c = count; - if (c++ > threshold) // ensure capacity - rehash(); - HashEntry[] tab = table; - int index = hash & (tab.length - 1); - HashEntry first = (HashEntry) tab[index]; - HashEntry e = first; - while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) - e = e.next; + V put(K key, int hash, V value, boolean onlyIfAbsent) { + lock(); + try { + int c = count; + if (c++ > threshold) // ensure capacity + rehash(); + HashEntry[] tab = table; + int index = hash & (tab.length - 1); + HashEntry first = (HashEntry) tab[index]; + HashEntry e = first; + while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) + e = e.next; - V oldValue; - if (e != null) { - oldValue = e.value; - if (!onlyIfAbsent) - e.value = value; - } - else { - oldValue = null; - ++modCount; - tab[index] = new HashEntry(key, hash, first, value); - count = c; // write-volatile - } - return oldValue; - } finally { - unlock(); - } + V oldValue; + if (e != null) { + oldValue = e.value; + if (!onlyIfAbsent) + e.value = value; } + else { + oldValue = null; + ++modCount; + tab[index] = new HashEntry(key, hash, first, value); + count = c; // write-volatile + } + return oldValue; + } finally { + unlock(); + } + } - void rehash() { - HashEntry[] oldTable = table; - int oldCapacity = oldTable.length; - if (oldCapacity >= MAXIMUM_CAPACITY) - return; + void rehash() { + HashEntry[] oldTable = table; + int oldCapacity = oldTable.length; + if (oldCapacity >= MAXIMUM_CAPACITY) + return; /* * Reclassify nodes in each list to new Map. Because we are @@ -398,103 +398,103 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * right now. */ - HashEntry[] newTable = new HashEntry[oldCapacity << 1]; - threshold = (int)(newTable.length * loadFactor); - int sizeMask = newTable.length - 1; - for (int i = 0; i < oldCapacity ; i++) { - // We need to guarantee that any existing reads of old Map can - // proceed. So we cannot yet null out each bin. - HashEntry e = (HashEntry)oldTable[i]; + HashEntry[] newTable = new HashEntry[oldCapacity << 1]; + threshold = (int)(newTable.length * loadFactor); + int sizeMask = newTable.length - 1; + for (int i = 0; i < oldCapacity ; i++) { + // We need to guarantee that any existing reads of old Map can + // proceed. So we cannot yet null out each bin. + HashEntry e = (HashEntry)oldTable[i]; - if (e != null) { - HashEntry next = e.next; - int idx = e.hash & sizeMask; + if (e != null) { + HashEntry next = e.next; + int idx = e.hash & sizeMask; - // Single node on list - if (next == null) - newTable[idx] = e; + // Single node on list + if (next == null) + newTable[idx] = e; - else { - // Reuse trailing consecutive sequence at same slot - HashEntry lastRun = e; - int lastIdx = idx; - for (HashEntry last = next; - last != null; - last = last.next) { - int k = last.hash & sizeMask; - if (k != lastIdx) { - lastIdx = k; - lastRun = last; - } - } - newTable[lastIdx] = lastRun; - - // Clone all remaining nodes - for (HashEntry p = e; p != lastRun; p = p.next) { - int k = p.hash & sizeMask; - HashEntry n = (HashEntry)newTable[k]; - newTable[k] = new HashEntry(p.key, p.hash, - n, p.value); - } - } - } + else { + // Reuse trailing consecutive sequence at same slot + HashEntry lastRun = e; + int lastIdx = idx; + for (HashEntry last = next; + last != null; + last = last.next) { + int k = last.hash & sizeMask; + if (k != lastIdx) { + lastIdx = k; + lastRun = last; + } } - table = newTable; - } + newTable[lastIdx] = lastRun; - /** - * Remove; match on key only if value null, else match both. - */ - V remove(K key, int hash, Object value) { - lock(); - try { - int c = count - 1; - HashEntry[] tab = table; - int index = hash & (tab.length - 1); - HashEntry first = (HashEntry)tab[index]; - HashEntry e = first; - while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) - e = e.next; - - V oldValue = null; - if (e != null) { - V v = e.value; - if (value == null || value.equals(v)) { - oldValue = v; - // All entries following removed node can stay - // in list, but all preceding ones need to be - // cloned. - ++modCount; - HashEntry newFirst = e.next; - for (HashEntry p = first; p != e; p = p.next) - newFirst = new HashEntry(p.key, p.hash, - newFirst, p.value); - tab[index] = newFirst; - count = c; // write-volatile - } - } - return oldValue; - } finally { - unlock(); - } - } - - void clear() { - if (count != 0) { - lock(); - try { - HashEntry[] tab = table; - for (int i = 0; i < tab.length ; i++) - tab[i] = null; - ++modCount; - count = 0; // write-volatile - } finally { - unlock(); - } + // Clone all remaining nodes + for (HashEntry p = e; p != lastRun; p = p.next) { + int k = p.hash & sizeMask; + HashEntry n = (HashEntry)newTable[k]; + newTable[k] = new HashEntry(p.key, p.hash, + n, p.value); } + } } + } + table = newTable; } + /** + * Remove; match on key only if value null, else match both. + */ + V remove(K key, int hash, Object value) { + lock(); + try { + int c = count - 1; + HashEntry[] tab = table; + int index = hash & (tab.length - 1); + HashEntry first = (HashEntry)tab[index]; + HashEntry e = first; + while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) + e = e.next; + + V oldValue = null; + if (e != null) { + V v = e.value; + if (value == null || value.equals(v)) { + oldValue = v; + // All entries following removed node can stay + // in list, but all preceding ones need to be + // cloned. + ++modCount; + HashEntry newFirst = e.next; + for (HashEntry p = first; p != e; p = p.next) + newFirst = new HashEntry(p.key, p.hash, + newFirst, p.value); + tab[index] = newFirst; + count = c; // write-volatile + } + } + return oldValue; + } finally { + unlock(); + } + } + + void clear() { + if (count != 0) { + lock(); + try { + HashEntry[] tab = table; + for (int i = 0; i < tab.length ; i++) + tab[i] = null; + ++modCount; + count = 0; // write-volatile + } finally { + unlock(); + } + } + } + } + /* ---------------- Public operations -------------- */ @@ -504,97 +504,97 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } /** - * 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. - */ - public ConcurrentHashMap(int initialCapacity, - float loadFactor, int concurrencyLevel) { + * 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. + */ + public ConcurrentHashMap(int initialCapacity, + float loadFactor, int concurrencyLevel) { this(initialCapacity,loadFactor, concurrencyLevel,null); } - public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, TObjectHashingStrategy hashingStrategy) { - if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) - throw new IllegalArgumentException(); + public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, TObjectHashingStrategy hashingStrategy) { + if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) + throw new IllegalArgumentException(); - if (concurrencyLevel > MAX_SEGMENTS) - concurrencyLevel = MAX_SEGMENTS; + 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; - } - segmentShift = 12; // the middle of the hash is much more random that its HSB. Especially when we use TObjectHashingStrategy.CANONICAl as a hash provider - segmentMask = ssize - 1; - segments = new Segment[ssize]; + // Find power-of-two sizes best matching arguments + int sshift = 0; + int ssize = 1; + while (ssize < concurrencyLevel) { + ++sshift; + ssize <<= 1; + } + segmentShift = 12; // the middle of the hash is much more random that its HSB. Especially when we use TObjectHashingStrategy.CANONICAl as a hash provider + segmentMask = ssize - 1; + segments = new Segment[ssize]; - if (initialCapacity > MAXIMUM_CAPACITY) - initialCapacity = MAXIMUM_CAPACITY; - int c = initialCapacity / ssize; - if (c * ssize < initialCapacity) - ++c; - int cap = 1; - while (cap < c) - cap <<= 1; + if (initialCapacity > MAXIMUM_CAPACITY) + initialCapacity = MAXIMUM_CAPACITY; + int c = initialCapacity / ssize; + if (c * ssize < initialCapacity) + ++c; + int cap = 1; + while (cap < c) + cap <<= 1; - hashingStrategy = hashingStrategy == null ? this : hashingStrategy; - for (int i = 0; i < segments.length; ++i) - segments[i] = new Segment(cap, loadFactor,hashingStrategy); + hashingStrategy = hashingStrategy == null ? this : hashingStrategy; + for (int i = 0; i < segments.length; ++i) + segments[i] = new Segment(cap, loadFactor,hashingStrategy); myHashingStrategy = hashingStrategy; - } + } - /** - * Creates a new, empty map with the specified initial - * capacity, and with default load factor and concurrencyLevel. - * - * @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_SEGMENTS); - } + /** + * Creates a new, empty map with the specified initial + * capacity, and with default load factor and concurrencyLevel. + * + * @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_SEGMENTS); + } - /** - * Creates a new, empty map with a default initial capacity, - * load factor, and concurrencyLevel. - */ - public ConcurrentHashMap() { - this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); - } + /** + * Creates a new, empty map with a default initial capacity, + * load factor, and concurrencyLevel. + */ + public ConcurrentHashMap() { + this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); + } - /** - * Creates a new map with the same mappings as the given map. The - * map is created with a capacity of twice the number of mappings in - * the given map or 11 (whichever is greater), and a default load factor - * and concurrencyLevel. - * @param t the map - */ - public ConcurrentHashMap(Map t) { - this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, - 11), - DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); - putAll(t); - } + /** + * Creates a new map with the same mappings as the given map. The + * map is created with a capacity of twice the number of mappings in + * the given map or 11 (whichever is greater), and a default load factor + * and concurrencyLevel. + * @param t the map + */ + public ConcurrentHashMap(Map t) { + this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, + 11), + DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); + putAll(t); + } - // inherit Map javadoc - @Override - public boolean isEmpty() { - final Segment[] segments = this.segments; + // inherit Map javadoc + @Override + public boolean isEmpty() { + final Segment[] segments = this.segments; /* * We keep track of per-segment modCounts to avoid ABA * problems in which an element in one segment was added and @@ -604,805 +604,805 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * methods, which are the only other methods also susceptible * to ABA problems. */ - int[] mc = new int[segments.length]; - int mcsum = 0; + int[] mc = new int[segments.length]; + int mcsum = 0; + for (int i = 0; i < segments.length; ++i) { + if (segments[i].count != 0) + return false; + else + mcsum += mc[i] = segments[i].modCount; + } + // If mcsum happens to be zero, then we know we got a snapshot + // before any modifications at all were made. This is + // probably common enough to bother tracking. + if (mcsum != 0) { + for (int i = 0; i < segments.length; ++i) { + if (segments[i].count != 0 || + mc[i] != segments[i].modCount) + return false; + } + } + return true; + } + + // inherit Map javadoc + @Override + public int size() { + final Segment[] segments = this.segments; + long sum = 0; + long check = 0; + int[] mc = new int[segments.length]; + // Try a few times to get accurate count. On failure due to + // continuous async changes in table, resort to locking. + for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { + check = 0; + sum = 0; + int mcsum = 0; + for (int i = 0; i < segments.length; ++i) { + sum += segments[i].count; + mcsum += mc[i] = segments[i].modCount; + } + if (mcsum != 0) { for (int i = 0; i < segments.length; ++i) { - if (segments[i].count != 0) - return false; - else - mcsum += mc[i] = segments[i].modCount; + check += segments[i].count; + if (mc[i] != segments[i].modCount) { + check = -1; // force retry + break; + } } - // If mcsum happens to be zero, then we know we got a snapshot - // before any modifications at all were made. This is - // probably common enough to bother tracking. - if (mcsum != 0) { - for (int i = 0; i < segments.length; ++i) { - if (segments[i].count != 0 || - mc[i] != segments[i].modCount) - return false; - } + } + if (check == sum) + break; + } + if (check != sum) { // Resort to locking all segments + sum = 0; + for (int i = 0; i < segments.length; ++i) + segments[i].lock(); + for (int i = 0; i < segments.length; ++i) + sum += segments[i].count; + for (int i = 0; i < segments.length; ++i) + segments[i].unlock(); + } + if (sum > Integer.MAX_VALUE) + return Integer.MAX_VALUE; + else + return (int)sum; + } + + + /** + * Returns the value to which the specified key is mapped in this table. + * + * @param key a key in the table. + * @return the value to which the key is mapped in this table; + * null if the key is not mapped to any value in + * this table. + * @throws NullPointerException if the key is + * null. + */ + @Override + public V get(Object key) { + int hash = myHashingStrategy.computeHashCode((K)key); // throws NullPointerException if key null + return segmentFor(hash).get((K)key, hash); + } + + /** + * Tests if the specified object is a key in this table. + * + * @param key possible key. + * @return true if and only if the specified object + * is a key in this table, as determined by the + * equals method; false otherwise. + * @throws NullPointerException if the key is + * null. + */ + @Override + public boolean containsKey(Object key) { + int hash = myHashingStrategy.computeHashCode((K)key); // throws NullPointerException if key null + return segmentFor(hash).containsKey((K)key, hash); + } + + /** + * Returns true 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 containsKey. + * + * @param value value whose presence in this map is to be tested. + * @return true if this map maps one or more keys to the + * specified value. + * @throws NullPointerException if the value is null. + */ + @Override + public boolean containsValue(@NotNull Object value) { + + // See explanation of modCount use above + + final Segment[] segments = this.segments; + int[] mc = new int[segments.length]; + + // Try a few times without locking + for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { + int sum = 0; + int mcsum = 0; + for (int i = 0; i < segments.length; ++i) { + int c = segments[i].count; + mcsum += mc[i] = segments[i].modCount; + if (segments[i].containsValue(value)) + return true; + } + boolean cleanSweep = true; + if (mcsum != 0) { + for (int i = 0; i < segments.length; ++i) { + int c = segments[i].count; + if (mc[i] != segments[i].modCount) { + cleanSweep = false; + break; + } } - return true; + } + if (cleanSweep) + return false; } - - // inherit Map javadoc - @Override - public int size() { - final Segment[] segments = this.segments; - long sum = 0; - long check = 0; - int[] mc = new int[segments.length]; - // Try a few times to get accurate count. On failure due to - // continuous async changes in table, resort to locking. - for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { - check = 0; - sum = 0; - int mcsum = 0; - for (int i = 0; i < segments.length; ++i) { - sum += segments[i].count; - mcsum += mc[i] = segments[i].modCount; - } - if (mcsum != 0) { - for (int i = 0; i < segments.length; ++i) { - check += segments[i].count; - if (mc[i] != segments[i].modCount) { - check = -1; // force retry - break; - } - } - } - if (check == sum) - break; + // Resort to locking all segments + for (int i = 0; i < segments.length; ++i) + segments[i].lock(); + boolean found = false; + try { + for (int i = 0; i < segments.length; ++i) { + if (segments[i].containsValue(value)) { + found = true; + break; } - if (check != sum) { // Resort to locking all segments - sum = 0; - for (int i = 0; i < segments.length; ++i) - segments[i].lock(); - for (int i = 0; i < segments.length; ++i) - sum += segments[i].count; - for (int i = 0; i < segments.length; ++i) - segments[i].unlock(); - } - if (sum > Integer.MAX_VALUE) - return Integer.MAX_VALUE; - else - return (int)sum; + } + } finally { + for (int i = 0; i < segments.length; ++i) + segments[i].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 true if and only if some key maps to the + * value argument in this table as + * determined by the equals method; + * false otherwise. + * @throws NullPointerException if the 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. + * + *

The value can be retrieved by calling the get method + * with a key that is equal to the original key. + * + * @param key the table key. + * @param value the value. + * @return the previous value of the specified key in this table, + * or null if it did not have one. + * @throws NullPointerException if the key or value is + * null. + */ + @Override + public V put(K key, @NotNull V value) { + int hash = myHashingStrategy.computeHashCode(key); + return segmentFor(hash).put(key, hash, value, false); + } + + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * This is equivalent to + *

+   *   if (!map.containsKey(key))
+   *      return map.put(key, value);
+   *   else
+   *      return map.get(key);
+   * 
+ * 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 previous value associated with specified key, or null + * if there was no mapping for key. + * @throws NullPointerException if the specified key or value is + * null. + */ + @Override + public V putIfAbsent(@NotNull K key, @NotNull V value) { + int hash = myHashingStrategy.computeHashCode(key); + return segmentFor(hash).put(key, hash, value, true); + } - /** - * Returns the value to which the specified key is mapped in this table. - * - * @param key a key in the table. - * @return the value to which the key is mapped in this table; - * null if the key is not mapped to any value in - * this table. - * @throws NullPointerException if the key is - * null. - */ - @Override - public V get(Object key) { - int hash = myHashingStrategy.computeHashCode((K)key); // throws NullPointerException if key null - return segmentFor(hash).get((K)key, hash); + /** + * Copies all of the mappings from the specified map to this one. + * + * These mappings replace any mappings that this map had for any of the + * keys currently in the specified Map. + * + * @param t Mappings to be stored in this map. + */ + @Override + public void putAll(Map t) { + for (Iterator> it = (Iterator>) t.entrySet().iterator(); it.hasNext(); ) { + Entry e = it.next(); + put(e.getKey(), e.getValue()); } + } - /** - * Tests if the specified object is a key in this table. - * - * @param key possible key. - * @return true if and only if the specified object - * is a key in this table, as determined by the - * equals method; false otherwise. - * @throws NullPointerException if the key is - * null. - */ - @Override - public boolean containsKey(Object key) { - int hash = myHashingStrategy.computeHashCode((K)key); // throws NullPointerException if key null - return segmentFor(hash).containsKey((K)key, hash); - } + /** + * Removes the key (and its corresponding value) from this + * table. This method does nothing if the key is not in the table. + * + * @param key the key that needs to be removed. + * @return the value to which the key had been mapped in this table, + * or null if the key did not have a mapping. + * @throws NullPointerException if the key is + * null. + */ + @Override + public V remove(Object key) { + int hash = myHashingStrategy.computeHashCode((K)key); + return segmentFor(hash).remove((K)key, hash, null); + } - /** - * Returns true 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 containsKey. - * - * @param value value whose presence in this map is to be tested. - * @return true if this map maps one or more keys to the - * specified value. - * @throws NullPointerException if the value is null. - */ - @Override - public boolean containsValue(@NotNull Object value) { - - // See explanation of modCount use above - - final Segment[] segments = this.segments; - int[] mc = new int[segments.length]; - - // Try a few times without locking - for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { - int sum = 0; - int mcsum = 0; - for (int i = 0; i < segments.length; ++i) { - int c = segments[i].count; - mcsum += mc[i] = segments[i].modCount; - if (segments[i].containsValue(value)) - return true; - } - boolean cleanSweep = true; - if (mcsum != 0) { - for (int i = 0; i < segments.length; ++i) { - int c = segments[i].count; - if (mc[i] != segments[i].modCount) { - cleanSweep = false; - break; - } - } - } - if (cleanSweep) - return false; - } - // Resort to locking all segments - for (int i = 0; i < segments.length; ++i) - segments[i].lock(); - boolean found = false; - try { - for (int i = 0; i < segments.length; ++i) { - if (segments[i].containsValue(value)) { - found = true; - break; - } - } - } finally { - for (int i = 0; i < segments.length; ++i) - segments[i].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 true if and only if some key maps to the - * value argument in this table as - * determined by the equals method; - * false otherwise. - * @throws NullPointerException if the 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. - * - *

The value can be retrieved by calling the get method - * with a key that is equal to the original key. - * - * @param key the table key. - * @param value the value. - * @return the previous value of the specified key in this table, - * or null if it did not have one. - * @throws NullPointerException if the key or value is - * null. - */ - @Override - public V put(K key, @NotNull V value) { - int hash = myHashingStrategy.computeHashCode(key); - return segmentFor(hash).put(key, hash, value, false); - } - - /** - * If the specified key is not already associated - * with a value, associate it with the given value. - * This is equivalent to - *

-     *   if (!map.containsKey(key))
-     *      return map.put(key, value);
-     *   else
-     *      return map.get(key);
-     * 
- * 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 previous value associated with specified key, or null - * if there was no mapping for key. - * @throws NullPointerException if the specified key or value is - * null. - */ - @Override - public V putIfAbsent(@NotNull K key, @NotNull V value) { - int hash = myHashingStrategy.computeHashCode(key); - return segmentFor(hash).put(key, hash, value, true); - } + /** + * Remove entry for key only if currently mapped to given value. + * Acts as + *
+   *  if (map.get(key).equals(value)) {
+   *     map.remove(key);
+   *     return true;
+   * } else return false;
+   * 
+ * except that the action is performed atomically. + * @param key key with which the specified value is associated. + * @param value value associated with the specified key. + * @return true if the value was removed + * @throws NullPointerException if the specified key is + * null. + */ + @Override + public boolean remove(@NotNull Object key, Object value) { + int hash = myHashingStrategy.computeHashCode((K)key); + return segmentFor(hash).remove((K)key, hash, value) != null; + } - /** - * Copies all of the mappings from the specified map to this one. - * - * These mappings replace any mappings that this map had for any of the - * keys currently in the specified Map. - * - * @param t Mappings to be stored in this map. - */ - @Override - public void putAll(Map t) { - for (Iterator> it = (Iterator>) t.entrySet().iterator(); it.hasNext(); ) { - Entry e = it.next(); - put(e.getKey(), e.getValue()); - } - } + /** + * Replace entry for key only if currently mapped to given value. + * Acts as + *
+   *  if (map.get(key).equals(oldValue)) {
+   *     map.put(key, newValue);
+   *     return true;
+   * } else return false;
+   * 
+ * 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 true if the value was replaced + * @throws NullPointerException if the specified key or values are + * null. + */ + @Override + public boolean replace(@NotNull K key, @NotNull V oldValue, @NotNull V newValue) { + int hash = myHashingStrategy.computeHashCode(key); + return segmentFor(hash).replace(key, hash, oldValue, newValue); + } - /** - * Removes the key (and its corresponding value) from this - * table. This method does nothing if the key is not in the table. - * - * @param key the key that needs to be removed. - * @return the value to which the key had been mapped in this table, - * or null if the key did not have a mapping. - * @throws NullPointerException if the key is - * null. - */ - @Override - public V remove(Object key) { - int hash = myHashingStrategy.computeHashCode((K)key); - return segmentFor(hash).remove((K)key, hash, null); - } - - /** - * Remove entry for key only if currently mapped to given value. - * Acts as - *
-     *  if (map.get(key).equals(value)) {
-     *     map.remove(key);
-     *     return true;
-     * } else return false;
-     * 
- * except that the action is performed atomically. - * @param key key with which the specified value is associated. - * @param value value associated with the specified key. - * @return true if the value was removed - * @throws NullPointerException if the specified key is - * null. - */ - @Override - public boolean remove(@NotNull Object key, Object value) { - int hash = myHashingStrategy.computeHashCode((K)key); - return segmentFor(hash).remove((K)key, hash, value) != null; - } + /** + * Replace entry for key only if currently mapped to some value. + * Acts as + *
+   *  if ((map.containsKey(key)) {
+   *     return map.put(key, value);
+   * } else return null;
+   * 
+ * 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 previous value associated with specified key, or null + * if there was no mapping for key. + * @throws NullPointerException if the specified key or value is + * null. + */ + @Override + public V replace(@NotNull K key, @NotNull V value) { + int hash = myHashingStrategy.computeHashCode(key); + return segmentFor(hash).replace(key, hash, value); + } - /** - * Replace entry for key only if currently mapped to given value. - * Acts as - *
-     *  if (map.get(key).equals(oldValue)) {
-     *     map.put(key, newValue);
-     *     return true;
-     * } else return false;
-     * 
- * 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 true if the value was replaced - * @throws NullPointerException if the specified key or values are - * null. - */ - @Override - public boolean replace(@NotNull K key, @NotNull V oldValue, @NotNull V newValue) { - int hash = myHashingStrategy.computeHashCode(key); - return segmentFor(hash).replace(key, hash, oldValue, newValue); - } + /** + * Removes all mappings from this map. + */ + @Override + public void clear() { + for (Segment segment : segments) segment.clear(); + } - /** - * Replace entry for key only if currently mapped to some value. - * Acts as - *
-     *  if ((map.containsKey(key)) {
-     *     return map.put(key, value);
-     * } else return null;
-     * 
- * 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 previous value associated with specified key, or null - * if there was no mapping for key. - * @throws NullPointerException if the specified key or value is - * null. - */ - @Override - public V replace(@NotNull K key, @NotNull V value) { - int hash = myHashingStrategy.computeHashCode(key); - return segmentFor(hash).replace(key, hash, value); - } + /** + * Returns a set view of the keys contained in this map. The set is + * backed by the map, so changes to the map are reflected in the set, and + * vice-versa. The set supports element removal, which removes the + * corresponding mapping from this map, via the Iterator.remove, + * Set.remove, removeAll, retainAll, and + * clear operations. It does not support the add or + * addAll operations. + * The view's returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.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. + * + * @return a set view of the keys contained in this map. + */ + @Override + public Set keySet() { + Set ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet()); + } - /** - * Removes all mappings from this map. - */ - @Override - public void clear() { - for (Segment segment : segments) segment.clear(); - } - - /** - * Returns a set view of the keys contained in this map. The set is - * backed by the map, so changes to the map are reflected in the set, and - * vice-versa. The set supports element removal, which removes the - * corresponding mapping from this map, via the Iterator.remove, - * Set.remove, removeAll, retainAll, and - * clear operations. It does not support the add or - * addAll operations. - * The view's returned iterator is a "weakly consistent" iterator that - * will never throw {@link java.util.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. - * - * @return a set view of the keys contained in this map. - */ - @Override - public Set keySet() { - Set ks = keySet; - return (ks != null) ? ks : (keySet = new KeySet()); - } + /** + * Returns a collection view of the values contained in this map. The + * collection is backed by the map, so changes to the map are reflected in + * the collection, and vice-versa. The collection supports element + * removal, which removes the corresponding mapping from this map, via the + * Iterator.remove, Collection.remove, + * removeAll, retainAll, and clear operations. + * It does not support the add or addAll operations. + * The view's returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.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. + * + * @return a collection view of the values contained in this map. + */ + @Override + public Collection values() { + Collection vs = values; + return (vs != null) ? vs : (values = new Values()); + } - /** - * Returns a collection view of the values contained in this map. The - * collection is backed by the map, so changes to the map are reflected in - * the collection, and vice-versa. The collection supports element - * removal, which removes the corresponding mapping from this map, via the - * Iterator.remove, Collection.remove, - * removeAll, retainAll, and clear operations. - * It does not support the add or addAll operations. - * The view's returned iterator is a "weakly consistent" iterator that - * will never throw {@link java.util.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. - * - * @return a collection view of the values contained in this map. - */ - @Override - public Collection values() { - Collection vs = values; - return (vs != null) ? vs : (values = new Values()); - } + /** + * Returns a collection view of the mappings contained in this map. Each + * element in the returned collection is a Map.Entry. The + * collection is backed by the map, so changes to the map are reflected in + * the collection, and vice-versa. The collection supports element + * removal, which removes the corresponding mapping from the map, via the + * Iterator.remove, Collection.remove, + * removeAll, retainAll, and clear operations. + * It does not support the add or addAll operations. + * The view's returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.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. + * + * @return a collection view of the mappings contained in this map. + */ + @Override + public Set> entrySet() { + Set> es = entrySet; + return (es != null) ? es : (entrySet = (Set>) (Set) new EntrySet()); + } - /** - * Returns a collection view of the mappings contained in this map. Each - * element in the returned collection is a Map.Entry. The - * collection is backed by the map, so changes to the map are reflected in - * the collection, and vice-versa. The collection supports element - * removal, which removes the corresponding mapping from the map, via the - * Iterator.remove, Collection.remove, - * removeAll, retainAll, and clear operations. - * It does not support the add or addAll operations. - * The view's returned iterator is a "weakly consistent" iterator that - * will never throw {@link java.util.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. - * - * @return a collection view of the mappings contained in this map. - */ - @Override - public Set> entrySet() { - Set> es = entrySet; - return (es != null) ? es : (entrySet = (Set>) (Set) new EntrySet()); - } + /** + * Returns an enumeration of the keys in this table. + * + * @return an enumeration of the keys in this table. + * @see #keySet + */ + public Enumeration keys() { + return new KeyIterator(); + } - - /** - * Returns an enumeration of the keys in this table. - * - * @return an enumeration of the keys in this table. - * @see #keySet - */ - public Enumeration 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 elements() { - return new ValueIterator(); - } + /** + * Returns an enumeration of the values in this table. + * + * @return an enumeration of the values in this table. + * @see #values + */ + public Enumeration elements() { + return new ValueIterator(); + } /* ---------------- Iterator Support -------------- */ - abstract class HashIterator { - int nextSegmentIndex; - int nextTableIndex; - HashEntry[] currentTable; - HashEntry nextEntry; - HashEntry lastReturned; + abstract class HashIterator { + int nextSegmentIndex; + int nextTableIndex; + HashEntry[] currentTable; + HashEntry nextEntry; + HashEntry lastReturned; - HashIterator() { - nextSegmentIndex = segments.length - 1; - nextTableIndex = -1; - advance(); - } + HashIterator() { + nextSegmentIndex = segments.length - 1; + nextTableIndex = -1; + advance(); + } - public boolean hasMoreElements() { return hasNext(); } + public boolean hasMoreElements() { return hasNext(); } - final void advance() { - if (nextEntry != null && (nextEntry = nextEntry.next) != null) - return; + final void advance() { + if (nextEntry != null && (nextEntry = nextEntry.next) != null) + return; - while (nextTableIndex >= 0) { - if ( (nextEntry = (HashEntry)currentTable[nextTableIndex--]) != null) - return; - } + while (nextTableIndex >= 0) { + if ( (nextEntry = (HashEntry)currentTable[nextTableIndex--]) != null) + return; + } - while (nextSegmentIndex >= 0) { - Segment seg = (Segment)segments[nextSegmentIndex--]; - if (seg.count != 0) { - currentTable = seg.table; - for (int j = currentTable.length - 1; j >= 0; --j) { - if ( (nextEntry = (HashEntry)currentTable[j]) != null) { - nextTableIndex = j - 1; - return; - } - } - } + while (nextSegmentIndex >= 0) { + Segment seg = (Segment)segments[nextSegmentIndex--]; + if (seg.count != 0) { + currentTable = seg.table; + for (int j = currentTable.length - 1; j >= 0; --j) { + if ( (nextEntry = (HashEntry)currentTable[j]) != null) { + nextTableIndex = j - 1; + return; } + } } - - public boolean hasNext() { return nextEntry != null; } - - HashEntry nextEntry() { - if (nextEntry == null) - throw new NoSuchElementException(); - lastReturned = nextEntry; - advance(); - return lastReturned; - } - - public void remove() { - if (lastReturned == null) - throw new IllegalStateException(); - ConcurrentHashMap.this.remove(lastReturned.key); - lastReturned = null; - } + } } - final class KeyIterator extends HashIterator implements Iterator, Enumeration { - @Override - public K next() { return super.nextEntry().key; } - @Override - public K nextElement() { return super.nextEntry().key; } + public boolean hasNext() { return nextEntry != null; } + + HashEntry nextEntry() { + if (nextEntry == null) + throw new NoSuchElementException(); + lastReturned = nextEntry; + advance(); + return lastReturned; } - final class ValueIterator extends HashIterator implements Iterator, Enumeration { - @Override - public V next() { return super.nextEntry().value; } - @Override - public V nextElement() { return super.nextEntry().value; } + public void remove() { + if (lastReturned == null) + throw new IllegalStateException(); + ConcurrentHashMap.this.remove(lastReturned.key); + lastReturned = null; + } + } + + final class KeyIterator extends HashIterator implements Iterator, Enumeration { + @Override + public K next() { return super.nextEntry().key; } + @Override + public K nextElement() { return super.nextEntry().key; } + } + + final class ValueIterator extends HashIterator implements Iterator, Enumeration { + @Override + public V next() { return super.nextEntry().value; } + @Override + public V nextElement() { return super.nextEntry().value; } + } + + + + /** + * Entry iterator. Exported Entry objects must write-through + * changes in setValue, even if the nodes have been cloned. So we + * cannot return internal HashEntry objects. Instead, the iterator + * itself acts as a forwarding pseudo-entry. + */ + final class EntryIterator extends HashIterator implements Entry, Iterator> { + @Override + public Entry next() { + nextEntry(); + return this; } - - - /** - * Entry iterator. Exported Entry objects must write-through - * changes in setValue, even if the nodes have been cloned. So we - * cannot return internal HashEntry objects. Instead, the iterator - * itself acts as a forwarding pseudo-entry. - */ - final class EntryIterator extends HashIterator implements Entry, Iterator> { - @Override - public Entry next() { - nextEntry(); - return this; - } - - @Override - public K getKey() { - if (lastReturned == null) - throw new IllegalStateException("Entry was removed"); - return lastReturned.key; - } - - @Override - public V getValue() { - if (lastReturned == null) - throw new IllegalStateException("Entry was removed"); - return get(lastReturned.key); - } - - @Override - public V setValue(V value) { - if (lastReturned == null) - throw new IllegalStateException("Entry was removed"); - return put(lastReturned.key, value); - } - - public boolean equals(Object o) { - // If not acting as entry, just use default. - if (lastReturned == null) - return super.equals(o); - if (!(o instanceof Entry)) - return false; - Entry e = (Entry)o; - K o1 = getKey(); - K o2 = (K)e.getKey(); - return (o1 == null ? o2 == null : myHashingStrategy.equals(o1,o2)) && eq(getValue(), e.getValue()); - } - - public int hashCode() { - // If not acting as entry, just use default. - if (lastReturned == null) - return super.hashCode(); - - Object k = getKey(); - Object v = getValue(); - return ((k == null) ? 0 : k.hashCode()) ^ - ((v == null) ? 0 : v.hashCode()); - } - - public String toString() { - // If not acting as entry, just use default. - if (lastReturned == null) - return super.toString(); - else - return getKey() + "=" + getValue(); - } - - boolean eq(Object o1, Object o2) { - return (o1 == null ? o2 == null : o1.equals(o2)); - } - + @Override + public K getKey() { + if (lastReturned == null) + throw new IllegalStateException("Entry was removed"); + return lastReturned.key; } - final class KeySet extends AbstractSet { - @Override - public Iterator iterator() { - return new KeyIterator(); - } - @Override - public int size() { - return ConcurrentHashMap.this.size(); - } - @Override - public boolean contains(Object o) { - return containsKey(o); - } - @Override - public boolean remove(Object o) { - return ConcurrentHashMap.this.remove(o) != null; - } - @Override - public void clear() { - ConcurrentHashMap.this.clear(); - } - @Override - public Object[] toArray() { - Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) - c.add(i.next()); - return c.toArray(); - } - @Override - public T[] toArray(T[] a) { - Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) - c.add(i.next()); - return c.toArray(a); - } + @Override + public V getValue() { + if (lastReturned == null) + throw new IllegalStateException("Entry was removed"); + return get(lastReturned.key); } - final class Values extends AbstractCollection { - @Override - public Iterator iterator() { - return new ValueIterator(); - } - @Override - public int size() { - return ConcurrentHashMap.this.size(); - } - @Override - public boolean contains(Object o) { - return containsValue(o); - } - @Override - public void clear() { - ConcurrentHashMap.this.clear(); - } - @Override - public Object[] toArray() { - Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) - c.add(i.next()); - return c.toArray(); - } - @Override - public T[] toArray(T[] a) { - Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) - c.add(i.next()); - return c.toArray(a); - } + @Override + public V setValue(V value) { + if (lastReturned == null) + throw new IllegalStateException("Entry was removed"); + return put(lastReturned.key, value); } - final class EntrySet extends AbstractSet> { - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - @Override - public boolean contains(Object o) { - if (!(o instanceof Entry)) - return false; - Entry e = (Entry)o; - V v = get(e.getKey()); - return v != null && v.equals(e.getValue()); - } - @Override - public boolean remove(Object o) { - if (!(o instanceof Entry)) - return false; - Entry e = (Entry)o; - return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()); - } - @Override - public int size() { - return ConcurrentHashMap.this.size(); - } - @Override - public void clear() { - ConcurrentHashMap.this.clear(); - } - @Override - public Object[] toArray() { - // Since we don't ordinarily have distinct Entry objects, we - // must pack elements using exportable SimpleEntry - Collection> c = new ArrayList>(size()); - for (Iterator> i = iterator(); i.hasNext(); ) - c.add(new SimpleEntry(i.next())); - return c.toArray(); - } - @Override - public T[] toArray(T[] a) { - Collection> c = new ArrayList>(size()); - for (Iterator> i = iterator(); i.hasNext(); ) - c.add(new SimpleEntry(i.next())); - return c.toArray(a); - } - + public boolean equals(Object o) { + // If not acting as entry, just use default. + if (lastReturned == null) + return super.equals(o); + if (!(o instanceof Entry)) + return false; + Entry e = (Entry)o; + K o1 = getKey(); + K o2 = (K)e.getKey(); + return (o1 == null ? o2 == null : myHashingStrategy.equals(o1,o2)) && eq(getValue(), e.getValue()); } - /** - * This duplicates java.util.AbstractMap.SimpleEntry until this class - * is made accessible. - */ - final class SimpleEntry implements Entry { - K key; - V value; + public int hashCode() { + // If not acting as entry, just use default. + if (lastReturned == null) + return super.hashCode(); - public SimpleEntry(K key, V value) { - this.key = key; - this.value = value; - } - - public SimpleEntry(Entry e) { - key = e.getKey(); - value = e.getValue(); - } - - @Override - public K getKey() { - return key; - } - - @Override - public V getValue() { - return value; - } - - @Override - public V setValue(V value) { - V oldValue = this.value; - this.value = value; - return oldValue; - } - - public boolean equals(Object o) { - if (!(o instanceof Entry)) - return false; - Entry e = (Entry)o; - K o2 = (K)e.getKey(); - return (key == null ? o2 == null : myHashingStrategy.equals(key,o2)) && eq(value, e.getValue()); - } - - public int hashCode() { - return ((key == null) ? 0 : key.hashCode()) ^ - ((value == null) ? 0 : value.hashCode()); - } - - public String toString() { - return key + "=" + value; - } - - boolean eq(Object o1, Object o2) { - return (o1 == null ? o2 == null : o1.equals(o2)); - } + Object k = getKey(); + Object v = getValue(); + return ((k == null) ? 0 : k.hashCode()) ^ + ((v == null) ? 0 : v.hashCode()); } + public String toString() { + // If not acting as entry, just use default. + if (lastReturned == null) + return super.toString(); + else + return getKey() + "=" + getValue(); + } + + boolean eq(Object o1, Object o2) { + return (o1 == null ? o2 == null : o1.equals(o2)); + } + + } + + final class KeySet extends AbstractSet { + @Override + public Iterator iterator() { + return new KeyIterator(); + } + @Override + public int size() { + return ConcurrentHashMap.this.size(); + } + @Override + public boolean contains(Object o) { + return containsKey(o); + } + @Override + public boolean remove(Object o) { + return ConcurrentHashMap.this.remove(o) != null; + } + @Override + public void clear() { + ConcurrentHashMap.this.clear(); + } + @Override + public Object[] toArray() { + Collection c = new ArrayList(); + for (Iterator i = iterator(); i.hasNext(); ) + c.add(i.next()); + return c.toArray(); + } + @Override + public T[] toArray(T[] a) { + Collection c = new ArrayList(); + for (Iterator i = iterator(); i.hasNext(); ) + c.add(i.next()); + return c.toArray(a); + } + } + + final class Values extends AbstractCollection { + @Override + public Iterator iterator() { + return new ValueIterator(); + } + @Override + public int size() { + return ConcurrentHashMap.this.size(); + } + @Override + public boolean contains(Object o) { + return containsValue(o); + } + @Override + public void clear() { + ConcurrentHashMap.this.clear(); + } + @Override + public Object[] toArray() { + Collection c = new ArrayList(); + for (Iterator i = iterator(); i.hasNext(); ) + c.add(i.next()); + return c.toArray(); + } + @Override + public T[] toArray(T[] a) { + Collection c = new ArrayList(); + for (Iterator i = iterator(); i.hasNext(); ) + c.add(i.next()); + return c.toArray(a); + } + } + + final class EntrySet extends AbstractSet> { + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + @Override + public boolean contains(Object o) { + if (!(o instanceof Entry)) + return false; + Entry e = (Entry)o; + V v = get(e.getKey()); + return v != null && v.equals(e.getValue()); + } + @Override + public boolean remove(Object o) { + if (!(o instanceof Entry)) + return false; + Entry e = (Entry)o; + return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()); + } + @Override + public int size() { + return ConcurrentHashMap.this.size(); + } + @Override + public void clear() { + ConcurrentHashMap.this.clear(); + } + @Override + public Object[] toArray() { + // Since we don't ordinarily have distinct Entry objects, we + // must pack elements using exportable SimpleEntry + Collection> c = new ArrayList>(size()); + for (Iterator> i = iterator(); i.hasNext(); ) + c.add(new SimpleEntry(i.next())); + return c.toArray(); + } + @Override + public T[] toArray(T[] a) { + Collection> c = new ArrayList>(size()); + for (Iterator> i = iterator(); i.hasNext(); ) + c.add(new SimpleEntry(i.next())); + return c.toArray(a); + } + + } + + /** + * This duplicates java.util.AbstractMap.SimpleEntry until this class + * is made accessible. + */ + final class SimpleEntry implements Entry { + K key; + V value; + + public SimpleEntry(K key, V value) { + this.key = key; + this.value = value; + } + + public SimpleEntry(Entry e) { + key = e.getKey(); + value = e.getValue(); + } + + @Override + public K getKey() { + return key; + } + + @Override + public V getValue() { + return value; + } + + @Override + public V setValue(V value) { + V oldValue = this.value; + this.value = value; + return oldValue; + } + + public boolean equals(Object o) { + if (!(o instanceof Entry)) + return false; + Entry e = (Entry)o; + K o2 = (K)e.getKey(); + return (key == null ? o2 == null : myHashingStrategy.equals(key,o2)) && eq(value, e.getValue()); + } + + public int hashCode() { + return ((key == null) ? 0 : key.hashCode()) ^ + ((value == null) ? 0 : value.hashCode()); + } + + public String toString() { + return key + "=" + value; + } + + boolean eq(Object o1, Object o2) { + return (o1 == null ? o2 == null : o1.equals(o2)); + } + } + /* ---------------- Serialization Support -------------- */ - /** - * Save the state of the ConcurrentHashMap - * 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 { - s.defaultWriteObject(); + /** + * Save the state of the ConcurrentHashMap + * 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 { + s.defaultWriteObject(); - for (int k = 0; k < segments.length; ++k) { - Segment seg = segments[k]; - seg.lock(); - try { - HashEntry[] tab = seg.table; - for (int i = 0; i < tab.length; ++i) { - for (HashEntry e = (HashEntry)tab[i]; e != null; e = e.next) { - s.writeObject(e.key); - s.writeObject(e.value); - } - } - } finally { - seg.unlock(); - } + for (int k = 0; k < segments.length; ++k) { + Segment seg = segments[k]; + seg.lock(); + try { + HashEntry[] tab = seg.table; + for (int i = 0; i < tab.length; ++i) { + for (HashEntry e = (HashEntry)tab[i]; e != null; e = e.next) { + s.writeObject(e.key); + s.writeObject(e.value); + } } - s.writeObject(null); - s.writeObject(null); + } finally { + seg.unlock(); + } + } + s.writeObject(null); + s.writeObject(null); + } + + /** + * Reconstitute the ConcurrentHashMap + * instance from a stream (i.e., + * deserialize it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + + // Initialize each segment to be minimally sized, and let grow. + for (int i = 0; i < segments.length; ++i) { + segments[i].setTable(new HashEntry[1]); } - /** - * Reconstitute the ConcurrentHashMap - * instance from a stream (i.e., - * deserialize it). - * @param s the stream - */ - private void readObject(java.io.ObjectInputStream s) - throws IOException, ClassNotFoundException { - s.defaultReadObject(); - - // Initialize each segment to be minimally sized, and let grow. - for (int i = 0; i < segments.length; ++i) { - segments[i].setTable(new HashEntry[1]); - } - - // 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); - } + // 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); } + } @Override public int computeHashCode(final K object) {