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