/** * 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) { if (value == null) throw new NullPointerException(); // See explanation of modCount use above final Segment<V>[] 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 (Segment<V> segment : segments) segment.lock(); boolean found = false; try { for (Segment<V> segment : segments) { if (segment.containsValue(value)) { found = true; break; } } } finally { for (Segment<V> segment : segments) segment.unlock(); } return found; }
/** * 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 { s.defaultWriteObject(); for (int k = 0; k < segments.length; ++k) { Segment<K, V> seg = (Segment<K, V>) segments[k]; seg.lock(); try { HashEntry[] tab = seg.table; for (int i = 0; i < tab.length; ++i) { for (HashEntry<K, V> e = (HashEntry<K, V>) tab[i]; e != null; e = e.next) { s.writeObject(e.key); s.writeObject(e.value); } } } finally { seg.unlock(); } } s.writeObject(null); s.writeObject(null); }
/** * 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 */ @Override public int size() { final Segment<V>[] 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; } if (check != sum) { // Resort to locking all segments sum = 0; for (Segment<V> segment : segments) segment.lock(); for (Segment<V> segment : segments) sum += segment.count; for (Segment<V> segment : segments) segment.unlock(); } if (sum > Integer.MAX_VALUE) return Integer.MAX_VALUE; else return (int) sum; }