ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentHashMap.java
(Generate patch)

Comparing jsr166/src/main/java/util/concurrent/ConcurrentHashMap.java (file contents):
Revision 1.252 by dl, Sun Dec 1 13:38:58 2013 UTC vs.
Revision 1.306 by jsr166, Sun Jan 7 21:53:40 2018 UTC

# Line 13 | Line 13 | import java.lang.reflect.Type;
13   import java.util.AbstractMap;
14   import java.util.Arrays;
15   import java.util.Collection;
16 import java.util.Comparator;
16   import java.util.Enumeration;
17   import java.util.HashMap;
18   import java.util.Hashtable;
# Line 22 | Line 21 | import java.util.Map;
21   import java.util.NoSuchElementException;
22   import java.util.Set;
23   import java.util.Spliterator;
25 import java.util.concurrent.ConcurrentMap;
26 import java.util.concurrent.ForkJoinPool;
24   import java.util.concurrent.atomic.AtomicReference;
25   import java.util.concurrent.locks.LockSupport;
26   import java.util.concurrent.locks.ReentrantLock;
27   import java.util.function.BiConsumer;
28   import java.util.function.BiFunction;
32 import java.util.function.BinaryOperator;
29   import java.util.function.Consumer;
30   import java.util.function.DoubleBinaryOperator;
31   import java.util.function.Function;
32   import java.util.function.IntBinaryOperator;
33   import java.util.function.LongBinaryOperator;
34 + import java.util.function.Predicate;
35   import java.util.function.ToDoubleBiFunction;
36   import java.util.function.ToDoubleFunction;
37   import java.util.function.ToIntBiFunction;
# Line 42 | Line 39 | import java.util.function.ToIntFunction;
39   import java.util.function.ToLongBiFunction;
40   import java.util.function.ToLongFunction;
41   import java.util.stream.Stream;
42 + import jdk.internal.misc.Unsafe;
43  
44   /**
45   * A hash table supporting full concurrency of retrievals and
# Line 104 | Line 102 | import java.util.stream.Stream;
102   * mapped values are (perhaps transiently) not used or all take the
103   * same mapping value.
104   *
105 < * <p>A ConcurrentHashMap can be used as scalable frequency map (a
105 > * <p>A ConcurrentHashMap can be used as a scalable frequency map (a
106   * form of histogram or multiset) by using {@link
107   * java.util.concurrent.atomic.LongAdder} values and initializing via
108   * {@link #computeIfAbsent computeIfAbsent}. For example, to add a count
109   * to a {@code ConcurrentHashMap<String,LongAdder> freqs}, you can use
110 < * {@code freqs.computeIfAbsent(k -> new LongAdder()).increment();}
110 > * {@code freqs.computeIfAbsent(key, k -> new LongAdder()).increment();}
111   *
112   * <p>This class and its views and iterators implement all of the
113   * <em>optional</em> methods of the {@link Map} and {@link Iterator}
# Line 124 | Line 122 | import java.util.stream.Stream;
122   * being concurrently updated by other threads; for example, when
123   * computing a snapshot summary of the values in a shared registry.
124   * There are three kinds of operation, each with four forms, accepting
125 < * functions with Keys, Values, Entries, and (Key, Value) arguments
126 < * and/or return values. Because the elements of a ConcurrentHashMap
127 < * are not ordered in any particular way, and may be processed in
128 < * different orders in different parallel executions, the correctness
129 < * of supplied functions should not depend on any ordering, or on any
130 < * other objects or values that may transiently change while
131 < * computation is in progress; and except for forEach actions, should
132 < * ideally be side-effect-free. Bulk operations on {@link java.util.Map.Entry}
133 < * objects do not support method {@code setValue}.
125 > * functions with keys, values, entries, and (key, value) pairs as
126 > * arguments and/or return values. Because the elements of a
127 > * ConcurrentHashMap are not ordered in any particular way, and may be
128 > * processed in different orders in different parallel executions, the
129 > * correctness of supplied functions should not depend on any
130 > * ordering, or on any other objects or values that may transiently
131 > * change while computation is in progress; and except for forEach
132 > * actions, should ideally be side-effect-free. Bulk operations on
133 > * {@link Map.Entry} objects do not support method {@code setValue}.
134   *
135   * <ul>
136 < * <li> forEach: Perform a given action on each element.
136 > * <li>forEach: Performs a given action on each element.
137   * A variant form applies a given transformation on each element
138 < * before performing the action.</li>
138 > * before performing the action.
139   *
140 < * <li> search: Return the first available non-null result of
140 > * <li>search: Returns the first available non-null result of
141   * applying a given function on each element; skipping further
142 < * search when a result is found.</li>
142 > * search when a result is found.
143   *
144 < * <li> reduce: Accumulate each element.  The supplied reduction
144 > * <li>reduce: Accumulates each element.  The supplied reduction
145   * function cannot rely on ordering (more formally, it should be
146   * both associative and commutative).  There are five variants:
147   *
148   * <ul>
149   *
150 < * <li> Plain reductions. (There is not a form of this method for
150 > * <li>Plain reductions. (There is not a form of this method for
151   * (key, value) function arguments since there is no corresponding
152 < * return type.)</li>
152 > * return type.)
153   *
154 < * <li> Mapped reductions that accumulate the results of a given
155 < * function applied to each element.</li>
154 > * <li>Mapped reductions that accumulate the results of a given
155 > * function applied to each element.
156   *
157 < * <li> Reductions to scalar doubles, longs, and ints, using a
158 < * given basis value.</li>
157 > * <li>Reductions to scalar doubles, longs, and ints, using a
158 > * given basis value.
159   *
160   * </ul>
163 * </li>
161   * </ul>
162   *
163   * <p>These bulk operations accept a {@code parallelismThreshold}
# Line 227 | Line 224 | import java.util.stream.Stream;
224   * <p>All arguments to all task methods must be non-null.
225   *
226   * <p>This class is a member of the
227 < * <a href="{@docRoot}/../technotes/guides/collections/index.html">
227 > * <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
228   * Java Collections Framework</a>.
229   *
230   * @since 1.5
# Line 271 | Line 268 | public class ConcurrentHashMap<K,V> exte
268       * Table accesses require volatile/atomic reads, writes, and
269       * CASes.  Because there is no other way to arrange this without
270       * adding further indirections, we use intrinsics
271 <     * (sun.misc.Unsafe) operations.
271 >     * (jdk.internal.misc.Unsafe) operations.
272       *
273       * We use the top (sign) bit of Node hash fields for control
274       * purposes -- it is available anyway because of addressing
# Line 451 | Line 448 | public class ConcurrentHashMap<K,V> exte
448       *
449       * Maintaining API and serialization compatibility with previous
450       * versions of this class introduces several oddities. Mainly: We
451 <     * leave untouched but unused constructor arguments refering to
451 >     * leave untouched but unused constructor arguments referring to
452       * concurrencyLevel. We accept a loadFactor constructor argument,
453       * but apply it only to initial table capacity (which is the only
454       * time that we can guarantee to honor it.) We also declare an
# Line 546 | Line 543 | public class ConcurrentHashMap<K,V> exte
543       * The number of bits used for generation stamp in sizeCtl.
544       * Must be at least 6 for 32bit arrays.
545       */
546 <    private static int RESIZE_STAMP_BITS = 16;
546 >    private static final int RESIZE_STAMP_BITS = 16;
547  
548      /**
549       * The maximum number of threads that can help resize.
# Line 570 | Line 567 | public class ConcurrentHashMap<K,V> exte
567      /** Number of CPUS, to place bounds on some sizings */
568      static final int NCPU = Runtime.getRuntime().availableProcessors();
569  
570 <    /** For serialization compatibility. */
570 >    /**
571 >     * Serialized pseudo-fields, provided only for jdk7 compatibility.
572 >     * @serialField segments Segment[]
573 >     *   The segments, each of which is a specialized hash table.
574 >     * @serialField segmentMask int
575 >     *   Mask value for indexing into segments. The upper bits of a
576 >     *   key's hash code are used to choose the segment.
577 >     * @serialField segmentShift int
578 >     *   Shift value for indexing within segments.
579 >     */
580      private static final ObjectStreamField[] serialPersistentFields = {
581          new ObjectStreamField("segments", Segment[].class),
582          new ObjectStreamField("segmentMask", Integer.TYPE),
583 <        new ObjectStreamField("segmentShift", Integer.TYPE)
583 >        new ObjectStreamField("segmentShift", Integer.TYPE),
584      };
585  
586      /* ---------------- Nodes -------------- */
# Line 593 | Line 599 | public class ConcurrentHashMap<K,V> exte
599          volatile V val;
600          volatile Node<K,V> next;
601  
602 <        Node(int hash, K key, V val, Node<K,V> next) {
602 >        Node(int hash, K key, V val) {
603              this.hash = hash;
604              this.key = key;
605              this.val = val;
606 +        }
607 +
608 +        Node(int hash, K key, V val, Node<K,V> next) {
609 +            this(hash, key, val);
610              this.next = next;
611          }
612  
613 <        public final K getKey()       { return key; }
614 <        public final V getValue()     { return val; }
615 <        public final int hashCode()   { return key.hashCode() ^ val.hashCode(); }
616 <        public final String toString(){ return key + "=" + val; }
613 >        public final K getKey()     { return key; }
614 >        public final V getValue()   { return val; }
615 >        public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
616 >        public final String toString() {
617 >            return Helpers.mapEntryToString(key, val);
618 >        }
619          public final V setValue(V value) {
620              throw new UnsupportedOperationException();
621          }
# Line 676 | Line 688 | public class ConcurrentHashMap<K,V> exte
688       */
689      static Class<?> comparableClassFor(Object x) {
690          if (x instanceof Comparable) {
691 <            Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
691 >            Class<?> c; Type[] ts, as; ParameterizedType p;
692              if ((c = x.getClass()) == String.class) // bypass checks
693                  return c;
694              if ((ts = c.getGenericInterfaces()) != null) {
695 <                for (int i = 0; i < ts.length; ++i) {
696 <                    if (((t = ts[i]) instanceof ParameterizedType) &&
695 >                for (Type t : ts) {
696 >                    if ((t instanceof ParameterizedType) &&
697                          ((p = (ParameterizedType)t).getRawType() ==
698                           Comparable.class) &&
699                          (as = p.getActualTypeArguments()) != null &&
# Line 706 | Line 718 | public class ConcurrentHashMap<K,V> exte
718      /* ---------------- Table element access -------------- */
719  
720      /*
721 <     * Volatile access methods are used for table elements as well as
721 >     * Atomic access methods are used for table elements as well as
722       * elements of in-progress next table while resizing.  All uses of
723       * the tab arguments must be null checked by callers.  All callers
724       * also paranoically precheck that tab's length is not zero (or an
# Line 716 | Line 728 | public class ConcurrentHashMap<K,V> exte
728       * errors by users, these checks must operate on local variables,
729       * which accounts for some odd-looking inline assignments below.
730       * Note that calls to setTabAt always occur within locked regions,
731 <     * and so in principle require only release ordering, not
720 <     * full volatile semantics, but are currently coded as volatile
721 <     * writes to be conservative.
731 >     * and so require only release ordering.
732       */
733  
734      @SuppressWarnings("unchecked")
735      static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
736 <        return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
736 >        return (Node<K,V>)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
737      }
738  
739      static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
740                                          Node<K,V> c, Node<K,V> v) {
741 <        return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
741 >        return U.compareAndSetObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
742      }
743  
744      static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
745 <        U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
745 >        U.putObjectRelease(tab, ((long)i << ASHIFT) + ABASE, v);
746      }
747  
748      /* ---------------- Fields -------------- */
# Line 983 | Line 993 | public class ConcurrentHashMap<K,V> exte
993          int hash = spread(key.hashCode());
994          int binCount = 0;
995          for (Node<K,V>[] tab = table;;) {
996 <            Node<K,V> f; int n, i, fh;
996 >            Node<K,V> f; int n, i, fh; K fk; V fv;
997              if (tab == null || (n = tab.length) == 0)
998                  tab = initTable();
999              else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
1000 <                if (casTabAt(tab, i, null,
991 <                             new Node<K,V>(hash, key, value, null)))
1000 >                if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
1001                      break;                   // no lock when adding to empty bin
1002              }
1003              else if ((fh = f.hash) == MOVED)
1004                  tab = helpTransfer(tab, f);
1005 +            else if (onlyIfAbsent // check first node without acquiring lock
1006 +                     && fh == hash
1007 +                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
1008 +                     && (fv = f.val) != null)
1009 +                return fv;
1010              else {
1011                  V oldVal = null;
1012                  synchronized (f) {
# Line 1011 | Line 1025 | public class ConcurrentHashMap<K,V> exte
1025                                  }
1026                                  Node<K,V> pred = e;
1027                                  if ((e = e.next) == null) {
1028 <                                    pred.next = new Node<K,V>(hash, key,
1015 <                                                              value, null);
1028 >                                    pred.next = new Node<K,V>(hash, key, value);
1029                                      break;
1030                                  }
1031                              }
# Line 1027 | Line 1040 | public class ConcurrentHashMap<K,V> exte
1040                                      p.val = value;
1041                              }
1042                          }
1043 +                        else if (f instanceof ReservationNode)
1044 +                            throw new IllegalStateException("Recursive update");
1045                      }
1046                  }
1047                  if (binCount != 0) {
# Line 1129 | Line 1144 | public class ConcurrentHashMap<K,V> exte
1144                                  }
1145                              }
1146                          }
1147 +                        else if (f instanceof ReservationNode)
1148 +                            throw new IllegalStateException("Recursive update");
1149                      }
1150                  }
1151                  if (validated) {
# Line 1199 | Line 1216 | public class ConcurrentHashMap<K,V> exte
1216       */
1217      public KeySetView<K,V> keySet() {
1218          KeySetView<K,V> ks;
1219 <        return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
1219 >        if ((ks = keySet) != null) return ks;
1220 >        return keySet = new KeySetView<K,V>(this, null);
1221      }
1222  
1223      /**
# Line 1222 | Line 1240 | public class ConcurrentHashMap<K,V> exte
1240       */
1241      public Collection<V> values() {
1242          ValuesView<K,V> vs;
1243 <        return (vs = values) != null ? vs : (values = new ValuesView<K,V>(this));
1243 >        if ((vs = values) != null) return vs;
1244 >        return values = new ValuesView<K,V>(this);
1245      }
1246  
1247      /**
# Line 1244 | Line 1263 | public class ConcurrentHashMap<K,V> exte
1263       */
1264      public Set<Map.Entry<K,V>> entrySet() {
1265          EntrySetView<K,V> es;
1266 <        return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K,V>(this));
1266 >        if ((es = entrySet) != null) return es;
1267 >        return entrySet = new EntrySetView<K,V>(this);
1268      }
1269  
1270      /**
# Line 1336 | Line 1356 | public class ConcurrentHashMap<K,V> exte
1356  
1357      /**
1358       * Stripped-down version of helper class used in previous version,
1359 <     * declared for the sake of serialization compatibility
1359 >     * declared for the sake of serialization compatibility.
1360       */
1361      static class Segment<K,V> extends ReentrantLock implements Serializable {
1362          private static final long serialVersionUID = 2249069246763182397L;
# Line 1345 | Line 1365 | public class ConcurrentHashMap<K,V> exte
1365      }
1366  
1367      /**
1368 <     * Saves the state of the {@code ConcurrentHashMap} instance to a
1369 <     * stream (i.e., serializes it).
1368 >     * Saves this map to a stream (that is, serializes it).
1369 >     *
1370       * @param s the stream
1371       * @throws java.io.IOException if an I/O error occurs
1372       * @serialData
1373 <     * the key (Object) and value (Object)
1374 <     * for each key-value mapping, followed by a null pair.
1373 >     * the serialized fields, followed by the key (Object) and value
1374 >     * (Object) for each key-value mapping, followed by a null pair.
1375       * The key-value mappings are emitted in no particular order.
1376       */
1377      private void writeObject(java.io.ObjectOutputStream s)
# Line 1371 | Line 1391 | public class ConcurrentHashMap<K,V> exte
1391              new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
1392          for (int i = 0; i < segments.length; ++i)
1393              segments[i] = new Segment<K,V>(LOAD_FACTOR);
1394 <        s.putFields().put("segments", segments);
1395 <        s.putFields().put("segmentShift", segmentShift);
1396 <        s.putFields().put("segmentMask", segmentMask);
1394 >        java.io.ObjectOutputStream.PutField streamFields = s.putFields();
1395 >        streamFields.put("segments", segments);
1396 >        streamFields.put("segmentShift", segmentShift);
1397 >        streamFields.put("segmentMask", segmentMask);
1398          s.writeFields();
1399  
1400          Node<K,V>[] t;
# Line 1386 | Line 1407 | public class ConcurrentHashMap<K,V> exte
1407          }
1408          s.writeObject(null);
1409          s.writeObject(null);
1389        segments = null; // throw away
1410      }
1411  
1412      /**
1413 <     * Reconstitutes the instance from a stream (that is, deserializes it).
1413 >     * Reconstitutes this map from a stream (that is, deserializes it).
1414       * @param s the stream
1415       * @throws ClassNotFoundException if the class of a serialized object
1416       *         could not be found
# Line 1590 | Line 1610 | public class ConcurrentHashMap<K,V> exte
1610      }
1611  
1612      /**
1613 +     * Helper method for EntrySetView.removeIf.
1614 +     */
1615 +    boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
1616 +        if (function == null) throw new NullPointerException();
1617 +        Node<K,V>[] t;
1618 +        boolean removed = false;
1619 +        if ((t = table) != null) {
1620 +            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
1621 +            for (Node<K,V> p; (p = it.advance()) != null; ) {
1622 +                K k = p.key;
1623 +                V v = p.val;
1624 +                Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
1625 +                if (function.test(e) && replaceNode(k, null, v) != null)
1626 +                    removed = true;
1627 +            }
1628 +        }
1629 +        return removed;
1630 +    }
1631 +
1632 +    /**
1633 +     * Helper method for ValuesView.removeIf.
1634 +     */
1635 +    boolean removeValueIf(Predicate<? super V> function) {
1636 +        if (function == null) throw new NullPointerException();
1637 +        Node<K,V>[] t;
1638 +        boolean removed = false;
1639 +        if ((t = table) != null) {
1640 +            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
1641 +            for (Node<K,V> p; (p = it.advance()) != null; ) {
1642 +                K k = p.key;
1643 +                V v = p.val;
1644 +                if (function.test(v) && replaceNode(k, null, v) != null)
1645 +                    removed = true;
1646 +            }
1647 +        }
1648 +        return removed;
1649 +    }
1650 +
1651 +    /**
1652       * If the specified key is not already associated with a value,
1653       * attempts to compute its value using the given mapping function
1654       * and enters it into this map unless {@code null}.  The entire
# Line 1618 | Line 1677 | public class ConcurrentHashMap<K,V> exte
1677          V val = null;
1678          int binCount = 0;
1679          for (Node<K,V>[] tab = table;;) {
1680 <            Node<K,V> f; int n, i, fh;
1680 >            Node<K,V> f; int n, i, fh; K fk; V fv;
1681              if (tab == null || (n = tab.length) == 0)
1682                  tab = initTable();
1683              else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
# Line 1629 | Line 1688 | public class ConcurrentHashMap<K,V> exte
1688                          Node<K,V> node = null;
1689                          try {
1690                              if ((val = mappingFunction.apply(key)) != null)
1691 <                                node = new Node<K,V>(h, key, val, null);
1691 >                                node = new Node<K,V>(h, key, val);
1692                          } finally {
1693                              setTabAt(tab, i, node);
1694                          }
# Line 1640 | Line 1699 | public class ConcurrentHashMap<K,V> exte
1699              }
1700              else if ((fh = f.hash) == MOVED)
1701                  tab = helpTransfer(tab, f);
1702 +            else if (fh == h    // check first node without acquiring lock
1703 +                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
1704 +                     && (fv = f.val) != null)
1705 +                return fv;
1706              else {
1707                  boolean added = false;
1708                  synchronized (f) {
# Line 1647 | Line 1710 | public class ConcurrentHashMap<K,V> exte
1710                          if (fh >= 0) {
1711                              binCount = 1;
1712                              for (Node<K,V> e = f;; ++binCount) {
1713 <                                K ek; V ev;
1713 >                                K ek;
1714                                  if (e.hash == h &&
1715                                      ((ek = e.key) == key ||
1716                                       (ek != null && key.equals(ek)))) {
# Line 1657 | Line 1720 | public class ConcurrentHashMap<K,V> exte
1720                                  Node<K,V> pred = e;
1721                                  if ((e = e.next) == null) {
1722                                      if ((val = mappingFunction.apply(key)) != null) {
1723 +                                        if (pred.next != null)
1724 +                                            throw new IllegalStateException("Recursive update");
1725                                          added = true;
1726 <                                        pred.next = new Node<K,V>(h, key, val, null);
1726 >                                        pred.next = new Node<K,V>(h, key, val);
1727                                      }
1728                                      break;
1729                                  }
# Line 1676 | Line 1741 | public class ConcurrentHashMap<K,V> exte
1741                                  t.putTreeVal(h, key, val);
1742                              }
1743                          }
1744 +                        else if (f instanceof ReservationNode)
1745 +                            throw new IllegalStateException("Recursive update");
1746                      }
1747                  }
1748                  if (binCount != 0) {
# Line 1771 | Line 1838 | public class ConcurrentHashMap<K,V> exte
1838                                  }
1839                              }
1840                          }
1841 +                        else if (f instanceof ReservationNode)
1842 +                            throw new IllegalStateException("Recursive update");
1843                      }
1844                  }
1845                  if (binCount != 0)
# Line 1823 | Line 1892 | public class ConcurrentHashMap<K,V> exte
1892                          try {
1893                              if ((val = remappingFunction.apply(key, null)) != null) {
1894                                  delta = 1;
1895 <                                node = new Node<K,V>(h, key, val, null);
1895 >                                node = new Node<K,V>(h, key, val);
1896                              }
1897                          } finally {
1898                              setTabAt(tab, i, node);
# Line 1862 | Line 1931 | public class ConcurrentHashMap<K,V> exte
1931                                  if ((e = e.next) == null) {
1932                                      val = remappingFunction.apply(key, null);
1933                                      if (val != null) {
1934 +                                        if (pred.next != null)
1935 +                                            throw new IllegalStateException("Recursive update");
1936                                          delta = 1;
1937 <                                        pred.next =
1867 <                                            new Node<K,V>(h, key, val, null);
1937 >                                        pred.next = new Node<K,V>(h, key, val);
1938                                      }
1939                                      break;
1940                                  }
# Line 1894 | Line 1964 | public class ConcurrentHashMap<K,V> exte
1964                                      setTabAt(tab, i, untreeify(t.first));
1965                              }
1966                          }
1967 +                        else if (f instanceof ReservationNode)
1968 +                            throw new IllegalStateException("Recursive update");
1969                      }
1970                  }
1971                  if (binCount != 0) {
# Line 1940 | Line 2012 | public class ConcurrentHashMap<K,V> exte
2012              if (tab == null || (n = tab.length) == 0)
2013                  tab = initTable();
2014              else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
2015 <                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value, null))) {
2015 >                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value))) {
2016                      delta = 1;
2017                      val = value;
2018                      break;
# Line 1975 | Line 2047 | public class ConcurrentHashMap<K,V> exte
2047                                  if ((e = e.next) == null) {
2048                                      delta = 1;
2049                                      val = value;
2050 <                                    pred.next =
1979 <                                        new Node<K,V>(h, key, val, null);
2050 >                                    pred.next = new Node<K,V>(h, key, val);
2051                                      break;
2052                                  }
2053                              }
# Line 2003 | Line 2074 | public class ConcurrentHashMap<K,V> exte
2074                                      setTabAt(tab, i, untreeify(t.first));
2075                              }
2076                          }
2077 +                        else if (f instanceof ReservationNode)
2078 +                            throw new IllegalStateException("Recursive update");
2079                      }
2080                  }
2081                  if (binCount != 0) {
# Line 2020 | Line 2093 | public class ConcurrentHashMap<K,V> exte
2093      // Hashtable legacy methods
2094  
2095      /**
2096 <     * Legacy method testing if some key maps into the specified value
2024 <     * in this table.
2096 >     * Tests if some key maps into the specified value in this table.
2097       *
2098 <     * @deprecated This method is identical in functionality to
2098 >     * <p>Note that this method is identical in functionality to
2099       * {@link #containsValue(Object)}, and exists solely to ensure
2100       * full compatibility with class {@link java.util.Hashtable},
2101       * which supported this method prior to introduction of the
2102 <     * Java Collections framework.
2102 >     * Java Collections Framework.
2103       *
2104       * @param  value a value to search for
2105       * @return {@code true} if and only if some key maps to the
# Line 2036 | Line 2108 | public class ConcurrentHashMap<K,V> exte
2108       *         {@code false} otherwise
2109       * @throws NullPointerException if the specified value is null
2110       */
2039    @Deprecated
2111      public boolean contains(Object value) {
2112          return containsValue(value);
2113      }
# Line 2137 | Line 2208 | public class ConcurrentHashMap<K,V> exte
2208      static final class ForwardingNode<K,V> extends Node<K,V> {
2209          final Node<K,V>[] nextTable;
2210          ForwardingNode(Node<K,V>[] tab) {
2211 <            super(MOVED, null, null, null);
2211 >            super(MOVED, null, null);
2212              this.nextTable = tab;
2213          }
2214  
# Line 2169 | Line 2240 | public class ConcurrentHashMap<K,V> exte
2240      }
2241  
2242      /**
2243 <     * A place-holder node used in computeIfAbsent and compute
2243 >     * A place-holder node used in computeIfAbsent and compute.
2244       */
2245      static final class ReservationNode<K,V> extends Node<K,V> {
2246          ReservationNode() {
2247 <            super(RESERVED, null, null, null);
2247 >            super(RESERVED, null, null);
2248          }
2249  
2250          Node<K,V> find(int h, Object k) {
# Line 2188 | Line 2259 | public class ConcurrentHashMap<K,V> exte
2259       * Must be negative when shifted left by RESIZE_STAMP_SHIFT.
2260       */
2261      static final int resizeStamp(int n) {
2262 <        return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
2262 >        return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
2263      }
2264  
2265      /**
# Line 2199 | Line 2270 | public class ConcurrentHashMap<K,V> exte
2270          while ((tab = table) == null || tab.length == 0) {
2271              if ((sc = sizeCtl) < 0)
2272                  Thread.yield(); // lost initialization race; just spin
2273 <            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
2273 >            else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
2274                  try {
2275                      if ((tab = table) == null || tab.length == 0) {
2276                          int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
# Line 2228 | Line 2299 | public class ConcurrentHashMap<K,V> exte
2299       * @param check if <0, don't check resize, if <= 1 only check if uncontended
2300       */
2301      private final void addCount(long x, int check) {
2302 <        CounterCell[] as; long b, s;
2303 <        if ((as = counterCells) != null ||
2304 <            !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
2305 <            CounterCell a; long v; int m;
2302 >        CounterCell[] cs; long b, s;
2303 >        if ((cs = counterCells) != null ||
2304 >            !U.compareAndSetLong(this, BASECOUNT, b = baseCount, s = b + x)) {
2305 >            CounterCell c; long v; int m;
2306              boolean uncontended = true;
2307 <            if (as == null || (m = as.length - 1) < 0 ||
2308 <                (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
2307 >            if (cs == null || (m = cs.length - 1) < 0 ||
2308 >                (c = cs[ThreadLocalRandom.getProbe() & m]) == null ||
2309                  !(uncontended =
2310 <                  U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
2310 >                  U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))) {
2311                  fullAddCount(x, uncontended);
2312                  return;
2313              }
# Line 2251 | Line 2322 | public class ConcurrentHashMap<K,V> exte
2322                  int rs = resizeStamp(n);
2323                  if (sc < 0) {
2324                      if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
2325 <                        sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
2326 <                        transferIndex <= 0)
2325 >                        sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
2326 >                        transferIndex <= 0)
2327                          break;
2328 <                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
2328 >                    if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1))
2329                          transfer(tab, nt);
2330                  }
2331 <                else if (U.compareAndSwapInt(this, SIZECTL, sc,
2332 <                                             (rs << RESIZE_STAMP_SHIFT) + 2))
2331 >                else if (U.compareAndSetInt(this, SIZECTL, sc,
2332 >                                             (rs << RESIZE_STAMP_SHIFT) + 2))
2333                      transfer(tab, null);
2334                  s = sumCount();
2335              }
# Line 2272 | Line 2343 | public class ConcurrentHashMap<K,V> exte
2343          Node<K,V>[] nextTab; int sc;
2344          if (tab != null && (f instanceof ForwardingNode) &&
2345              (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
2346 <            int rs = resizeStamp(tab.length);
2346 >            int rs = resizeStamp(tab.length);
2347              while (nextTab == nextTable && table == tab &&
2348 <                   (sc = sizeCtl) < 0) {
2349 <                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
2348 >                   (sc = sizeCtl) < 0) {
2349 >                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
2350                      sc == rs + MAX_RESIZERS || transferIndex <= 0)
2351 <                    break;
2352 <                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
2351 >                    break;
2352 >                if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1)) {
2353                      transfer(tab, nextTab);
2354                      break;
2355                  }
# Line 2301 | Line 2372 | public class ConcurrentHashMap<K,V> exte
2372              Node<K,V>[] tab = table; int n;
2373              if (tab == null || (n = tab.length) == 0) {
2374                  n = (sc > c) ? sc : c;
2375 <                if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
2375 >                if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
2376                      try {
2377                          if (table == tab) {
2378                              @SuppressWarnings("unchecked")
# Line 2318 | Line 2389 | public class ConcurrentHashMap<K,V> exte
2389                  break;
2390              else if (tab == table) {
2391                  int rs = resizeStamp(n);
2392 <                if (sc < 0) {
2393 <                    Node<K,V>[] nt;
2323 <                    if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
2324 <                        sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
2325 <                        transferIndex <= 0)
2326 <                        break;
2327 <                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
2328 <                        transfer(tab, nt);
2329 <                }
2330 <                else if (U.compareAndSwapInt(this, SIZECTL, sc,
2331 <                                             (rs << RESIZE_STAMP_SHIFT) + 2))
2392 >                if (U.compareAndSetInt(this, SIZECTL, sc,
2393 >                                        (rs << RESIZE_STAMP_SHIFT) + 2))
2394                      transfer(tab, null);
2395              }
2396          }
# Line 2368 | Line 2430 | public class ConcurrentHashMap<K,V> exte
2430                      i = -1;
2431                      advance = false;
2432                  }
2433 <                else if (U.compareAndSwapInt
2433 >                else if (U.compareAndSetInt
2434                           (this, TRANSFERINDEX, nextIndex,
2435                            nextBound = (nextIndex > stride ?
2436                                         nextIndex - stride : 0))) {
# Line 2385 | Line 2447 | public class ConcurrentHashMap<K,V> exte
2447                      sizeCtl = (n << 1) - (n >>> 1);
2448                      return;
2449                  }
2450 <                if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
2451 <                    if ((sc - 2) != resizeStamp(n))
2450 >                if (U.compareAndSetInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
2451 >                    if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
2452                          return;
2453                      finishing = advance = true;
2454                      i = n; // recheck before commit
# Line 2477 | Line 2539 | public class ConcurrentHashMap<K,V> exte
2539       * A padded cell for distributing counts.  Adapted from LongAdder
2540       * and Striped64.  See their internal docs for explanation.
2541       */
2542 <    @sun.misc.Contended static final class CounterCell {
2542 >    @jdk.internal.vm.annotation.Contended static final class CounterCell {
2543          volatile long value;
2544          CounterCell(long x) { value = x; }
2545      }
2546  
2547      final long sumCount() {
2548 <        CounterCell[] as = counterCells; CounterCell a;
2548 >        CounterCell[] cs = counterCells;
2549          long sum = baseCount;
2550 <        if (as != null) {
2551 <            for (int i = 0; i < as.length; ++i) {
2552 <                if ((a = as[i]) != null)
2553 <                    sum += a.value;
2492 <            }
2550 >        if (cs != null) {
2551 >            for (CounterCell c : cs)
2552 >                if (c != null)
2553 >                    sum += c.value;
2554          }
2555          return sum;
2556      }
# Line 2504 | Line 2565 | public class ConcurrentHashMap<K,V> exte
2565          }
2566          boolean collide = false;                // True if last slot nonempty
2567          for (;;) {
2568 <            CounterCell[] as; CounterCell a; int n; long v;
2569 <            if ((as = counterCells) != null && (n = as.length) > 0) {
2570 <                if ((a = as[(n - 1) & h]) == null) {
2568 >            CounterCell[] cs; CounterCell c; int n; long v;
2569 >            if ((cs = counterCells) != null && (n = cs.length) > 0) {
2570 >                if ((c = cs[(n - 1) & h]) == null) {
2571                      if (cellsBusy == 0) {            // Try to attach new Cell
2572                          CounterCell r = new CounterCell(x); // Optimistic create
2573                          if (cellsBusy == 0 &&
2574 <                            U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
2574 >                            U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
2575                              boolean created = false;
2576                              try {               // Recheck under lock
2577                                  CounterCell[] rs; int m, j;
# Line 2532 | Line 2593 | public class ConcurrentHashMap<K,V> exte
2593                  }
2594                  else if (!wasUncontended)       // CAS already known to fail
2595                      wasUncontended = true;      // Continue after rehash
2596 <                else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
2596 >                else if (U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))
2597                      break;
2598 <                else if (counterCells != as || n >= NCPU)
2598 >                else if (counterCells != cs || n >= NCPU)
2599                      collide = false;            // At max size or stale
2600                  else if (!collide)
2601                      collide = true;
2602                  else if (cellsBusy == 0 &&
2603 <                         U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
2603 >                         U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
2604                      try {
2605 <                        if (counterCells == as) {// Expand table unless stale
2606 <                            CounterCell[] rs = new CounterCell[n << 1];
2546 <                            for (int i = 0; i < n; ++i)
2547 <                                rs[i] = as[i];
2548 <                            counterCells = rs;
2549 <                        }
2605 >                        if (counterCells == cs) // Expand table unless stale
2606 >                            counterCells = Arrays.copyOf(cs, n << 1);
2607                      } finally {
2608                          cellsBusy = 0;
2609                      }
# Line 2555 | Line 2612 | public class ConcurrentHashMap<K,V> exte
2612                  }
2613                  h = ThreadLocalRandom.advanceProbe(h);
2614              }
2615 <            else if (cellsBusy == 0 && counterCells == as &&
2616 <                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
2615 >            else if (cellsBusy == 0 && counterCells == cs &&
2616 >                     U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
2617                  boolean init = false;
2618                  try {                           // Initialize table
2619 <                    if (counterCells == as) {
2619 >                    if (counterCells == cs) {
2620                          CounterCell[] rs = new CounterCell[2];
2621                          rs[h & 1] = new CounterCell(x);
2622                          counterCells = rs;
# Line 2571 | Line 2628 | public class ConcurrentHashMap<K,V> exte
2628                  if (init)
2629                      break;
2630              }
2631 <            else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
2631 >            else if (U.compareAndSetLong(this, BASECOUNT, v = baseCount, v + x))
2632                  break;                          // Fall back on using base
2633          }
2634      }
# Line 2583 | Line 2640 | public class ConcurrentHashMap<K,V> exte
2640       * too small, in which case resizes instead.
2641       */
2642      private final void treeifyBin(Node<K,V>[] tab, int index) {
2643 <        Node<K,V> b; int n, sc;
2643 >        Node<K,V> b; int n;
2644          if (tab != null) {
2645              if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
2646                  tryPresize(n << 1);
# Line 2609 | Line 2666 | public class ConcurrentHashMap<K,V> exte
2666      }
2667  
2668      /**
2669 <     * Returns a list on non-TreeNodes replacing those in given list.
2669 >     * Returns a list of non-TreeNodes replacing those in given list.
2670       */
2671      static <K,V> Node<K,V> untreeify(Node<K,V> b) {
2672          Node<K,V> hd = null, tl = null;
2673          for (Node<K,V> q = b; q != null; q = q.next) {
2674 <            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val, null);
2674 >            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val);
2675              if (tl == null)
2676                  hd = p;
2677              else
# Line 2627 | Line 2684 | public class ConcurrentHashMap<K,V> exte
2684      /* ---------------- TreeNodes -------------- */
2685  
2686      /**
2687 <     * Nodes for use in TreeBins
2687 >     * Nodes for use in TreeBins.
2688       */
2689      static final class TreeNode<K,V> extends Node<K,V> {
2690          TreeNode<K,V> parent;  // red-black tree links
# Line 2653 | Line 2710 | public class ConcurrentHashMap<K,V> exte
2710          final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
2711              if (k != null) {
2712                  TreeNode<K,V> p = this;
2713 <                do  {
2713 >                do {
2714                      int ph, dir; K pk; TreeNode<K,V> q;
2715                      TreeNode<K,V> pl = p.left, pr = p.right;
2716                      if ((ph = p.hash) > h)
# Line 2720 | Line 2777 | public class ConcurrentHashMap<K,V> exte
2777           * Creates bin with initial set of nodes headed by b.
2778           */
2779          TreeBin(TreeNode<K,V> b) {
2780 <            super(TREEBIN, null, null, null);
2780 >            super(TREEBIN, null, null);
2781              this.first = b;
2782              TreeNode<K,V> r = null;
2783              for (TreeNode<K,V> x = b, next; x != null; x = next) {
# Line 2746 | Line 2803 | public class ConcurrentHashMap<K,V> exte
2803                                    (kc = comparableClassFor(k)) == null) ||
2804                                   (dir = compareComparables(kc, k, pk)) == 0)
2805                              dir = tieBreakOrder(k, pk);
2806 <                            TreeNode<K,V> xp = p;
2806 >                        TreeNode<K,V> xp = p;
2807                          if ((p = (dir <= 0) ? p.left : p.right) == null) {
2808                              x.parent = xp;
2809                              if (dir <= 0)
# Line 2767 | Line 2824 | public class ConcurrentHashMap<K,V> exte
2824           * Acquires write lock for tree restructuring.
2825           */
2826          private final void lockRoot() {
2827 <            if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
2827 >            if (!U.compareAndSetInt(this, LOCKSTATE, 0, WRITER))
2828                  contendedLock(); // offload to separate method
2829          }
2830  
# Line 2785 | Line 2842 | public class ConcurrentHashMap<K,V> exte
2842              boolean waiting = false;
2843              for (int s;;) {
2844                  if (((s = lockState) & ~WAITER) == 0) {
2845 <                    if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
2845 >                    if (U.compareAndSetInt(this, LOCKSTATE, s, WRITER)) {
2846                          if (waiting)
2847                              waiter = null;
2848                          return;
2849                      }
2850                  }
2851                  else if ((s & WAITER) == 0) {
2852 <                    if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
2852 >                    if (U.compareAndSetInt(this, LOCKSTATE, s, s | WAITER)) {
2853                          waiting = true;
2854                          waiter = Thread.currentThread();
2855                      }
# Line 2809 | Line 2866 | public class ConcurrentHashMap<K,V> exte
2866           */
2867          final Node<K,V> find(int h, Object k) {
2868              if (k != null) {
2869 <                for (Node<K,V> e = first; e != null; e = e.next) {
2869 >                for (Node<K,V> e = first; e != null; ) {
2870                      int s; K ek;
2871                      if (((s = lockState) & (WAITER|WRITER)) != 0) {
2872                          if (e.hash == h &&
2873                              ((ek = e.key) == k || (ek != null && k.equals(ek))))
2874                              return e;
2875 +                        e = e.next;
2876                      }
2877 <                    else if (U.compareAndSwapInt(this, LOCKSTATE, s,
2877 >                    else if (U.compareAndSetInt(this, LOCKSTATE, s,
2878                                                   s + READER)) {
2879                          TreeNode<K,V> r, p;
2880                          try {
# Line 3098 | Line 3156 | public class ConcurrentHashMap<K,V> exte
3156  
3157          static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
3158                                                     TreeNode<K,V> x) {
3159 <            for (TreeNode<K,V> xp, xpl, xpr;;)  {
3159 >            for (TreeNode<K,V> xp, xpl, xpr;;) {
3160                  if (x == null || x == root)
3161                      return root;
3162                  else if ((xp = x.parent) == null) {
# Line 3189 | Line 3247 | public class ConcurrentHashMap<K,V> exte
3247          }
3248  
3249          /**
3250 <         * Recursive invariant check
3250 >         * Checks invariants recursively for the tree of Nodes rooted at t.
3251           */
3252          static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
3253              TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
# Line 3213 | Line 3271 | public class ConcurrentHashMap<K,V> exte
3271              return true;
3272          }
3273  
3274 <        private static final sun.misc.Unsafe U;
3274 >        private static final Unsafe U = Unsafe.getUnsafe();
3275          private static final long LOCKSTATE;
3276          static {
3277              try {
3220                U = sun.misc.Unsafe.getUnsafe();
3221                Class<?> k = TreeBin.class;
3278                  LOCKSTATE = U.objectFieldOffset
3279 <                    (k.getDeclaredField("lockState"));
3280 <            } catch (Exception e) {
3279 >                    (TreeBin.class.getDeclaredField("lockState"));
3280 >            } catch (ReflectiveOperationException e) {
3281                  throw new Error(e);
3282              }
3283          }
# Line 3378 | Line 3434 | public class ConcurrentHashMap<K,V> exte
3434  
3435      static final class KeyIterator<K,V> extends BaseIterator<K,V>
3436          implements Iterator<K>, Enumeration<K> {
3437 <        KeyIterator(Node<K,V>[] tab, int index, int size, int limit,
3437 >        KeyIterator(Node<K,V>[] tab, int size, int index, int limit,
3438                      ConcurrentHashMap<K,V> map) {
3439 <            super(tab, index, size, limit, map);
3439 >            super(tab, size, index, limit, map);
3440          }
3441  
3442          public final K next() {
# Line 3398 | Line 3454 | public class ConcurrentHashMap<K,V> exte
3454  
3455      static final class ValueIterator<K,V> extends BaseIterator<K,V>
3456          implements Iterator<V>, Enumeration<V> {
3457 <        ValueIterator(Node<K,V>[] tab, int index, int size, int limit,
3457 >        ValueIterator(Node<K,V>[] tab, int size, int index, int limit,
3458                        ConcurrentHashMap<K,V> map) {
3459 <            super(tab, index, size, limit, map);
3459 >            super(tab, size, index, limit, map);
3460          }
3461  
3462          public final V next() {
# Line 3418 | Line 3474 | public class ConcurrentHashMap<K,V> exte
3474  
3475      static final class EntryIterator<K,V> extends BaseIterator<K,V>
3476          implements Iterator<Map.Entry<K,V>> {
3477 <        EntryIterator(Node<K,V>[] tab, int index, int size, int limit,
3477 >        EntryIterator(Node<K,V>[] tab, int size, int index, int limit,
3478                        ConcurrentHashMap<K,V> map) {
3479 <            super(tab, index, size, limit, map);
3479 >            super(tab, size, index, limit, map);
3480          }
3481  
3482          public final Map.Entry<K,V> next() {
# Line 3436 | Line 3492 | public class ConcurrentHashMap<K,V> exte
3492      }
3493  
3494      /**
3495 <     * Exported Entry for EntryIterator
3495 >     * Exported Entry for EntryIterator.
3496       */
3497      static final class MapEntry<K,V> implements Map.Entry<K,V> {
3498          final K key; // non-null
# Line 3450 | Line 3506 | public class ConcurrentHashMap<K,V> exte
3506          public K getKey()        { return key; }
3507          public V getValue()      { return val; }
3508          public int hashCode()    { return key.hashCode() ^ val.hashCode(); }
3509 <        public String toString() { return key + "=" + val; }
3509 >        public String toString() {
3510 >            return Helpers.mapEntryToString(key, val);
3511 >        }
3512  
3513          public boolean equals(Object o) {
3514              Object k, v; Map.Entry<?,?> e;
# Line 3487 | Line 3545 | public class ConcurrentHashMap<K,V> exte
3545              this.est = est;
3546          }
3547  
3548 <        public Spliterator<K> trySplit() {
3548 >        public KeySpliterator<K,V> trySplit() {
3549              int i, f, h;
3550              return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
3551                  new KeySpliterator<K,V>(tab, baseSize, baseLimit = h,
# Line 3526 | Line 3584 | public class ConcurrentHashMap<K,V> exte
3584              this.est = est;
3585          }
3586  
3587 <        public Spliterator<V> trySplit() {
3587 >        public ValueSpliterator<K,V> trySplit() {
3588              int i, f, h;
3589              return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
3590                  new ValueSpliterator<K,V>(tab, baseSize, baseLimit = h,
# Line 3566 | Line 3624 | public class ConcurrentHashMap<K,V> exte
3624              this.est = est;
3625          }
3626  
3627 <        public Spliterator<Map.Entry<K,V>> trySplit() {
3627 >        public EntrySpliterator<K,V> trySplit() {
3628              int i, f, h;
3629              return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
3630                  new EntrySpliterator<K,V>(tab, baseSize, baseLimit = h,
# Line 4378 | Line 4436 | public class ConcurrentHashMap<K,V> exte
4436          public abstract boolean contains(Object o);
4437          public abstract boolean remove(Object o);
4438  
4439 <        private static final String oomeMsg = "Required array size too large";
4439 >        private static final String OOME_MSG = "Required array size too large";
4440  
4441          public final Object[] toArray() {
4442              long sz = map.mappingCount();
4443              if (sz > MAX_ARRAY_SIZE)
4444 <                throw new OutOfMemoryError(oomeMsg);
4444 >                throw new OutOfMemoryError(OOME_MSG);
4445              int n = (int)sz;
4446              Object[] r = new Object[n];
4447              int i = 0;
4448              for (E e : this) {
4449                  if (i == n) {
4450                      if (n >= MAX_ARRAY_SIZE)
4451 <                        throw new OutOfMemoryError(oomeMsg);
4451 >                        throw new OutOfMemoryError(OOME_MSG);
4452                      if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
4453                          n = MAX_ARRAY_SIZE;
4454                      else
# Line 4406 | Line 4464 | public class ConcurrentHashMap<K,V> exte
4464          public final <T> T[] toArray(T[] a) {
4465              long sz = map.mappingCount();
4466              if (sz > MAX_ARRAY_SIZE)
4467 <                throw new OutOfMemoryError(oomeMsg);
4467 >                throw new OutOfMemoryError(OOME_MSG);
4468              int m = (int)sz;
4469              T[] r = (a.length >= m) ? a :
4470                  (T[])java.lang.reflect.Array
# Line 4416 | Line 4474 | public class ConcurrentHashMap<K,V> exte
4474              for (E e : this) {
4475                  if (i == n) {
4476                      if (n >= MAX_ARRAY_SIZE)
4477 <                        throw new OutOfMemoryError(oomeMsg);
4477 >                        throw new OutOfMemoryError(OOME_MSG);
4478                      if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
4479                          n = MAX_ARRAY_SIZE;
4480                      else
# Line 4469 | Line 4527 | public class ConcurrentHashMap<K,V> exte
4527              return true;
4528          }
4529  
4530 <        public final boolean removeAll(Collection<?> c) {
4530 >        public boolean removeAll(Collection<?> c) {
4531              if (c == null) throw new NullPointerException();
4532              boolean modified = false;
4533 <            for (Iterator<E> it = iterator(); it.hasNext();) {
4534 <                if (c.contains(it.next())) {
4535 <                    it.remove();
4536 <                    modified = true;
4533 >            // Use (c instanceof Set) as a hint that lookup in c is as
4534 >            // efficient as this view
4535 >            Node<K,V>[] t;
4536 >            if ((t = map.table) == null) {
4537 >                return false;
4538 >            } else if (c instanceof Set<?> && c.size() > t.length) {
4539 >                for (Iterator<?> it = iterator(); it.hasNext(); ) {
4540 >                    if (c.contains(it.next())) {
4541 >                        it.remove();
4542 >                        modified = true;
4543 >                    }
4544                  }
4545 +            } else {
4546 +                for (Object e : c)
4547 +                    modified |= remove(e);
4548              }
4549              return modified;
4550          }
# Line 4663 | Line 4731 | public class ConcurrentHashMap<K,V> exte
4731              throw new UnsupportedOperationException();
4732          }
4733  
4734 +        @Override public boolean removeAll(Collection<?> c) {
4735 +            if (c == null) throw new NullPointerException();
4736 +            boolean modified = false;
4737 +            for (Iterator<V> it = iterator(); it.hasNext();) {
4738 +                if (c.contains(it.next())) {
4739 +                    it.remove();
4740 +                    modified = true;
4741 +                }
4742 +            }
4743 +            return modified;
4744 +        }
4745 +
4746 +        public boolean removeIf(Predicate<? super V> filter) {
4747 +            return map.removeValueIf(filter);
4748 +        }
4749 +
4750          public Spliterator<V> spliterator() {
4751              Node<K,V>[] t;
4752              ConcurrentHashMap<K,V> m = map;
# Line 4732 | Line 4816 | public class ConcurrentHashMap<K,V> exte
4816              return added;
4817          }
4818  
4819 +        public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
4820 +            return map.removeEntryIf(filter);
4821 +        }
4822 +
4823          public final int hashCode() {
4824              int h = 0;
4825              Node<K,V>[] t;
# Line 4803 | Line 4891 | public class ConcurrentHashMap<K,V> exte
4891          }
4892  
4893          /**
4894 <         * Same as Traverser version
4894 >         * Same as Traverser version.
4895           */
4896          final Node<K,V> advance() {
4897              Node<K,V> e;
# Line 6248 | Line 6336 | public class ConcurrentHashMap<K,V> exte
6336      }
6337  
6338      // Unsafe mechanics
6339 <    private static final sun.misc.Unsafe U;
6339 >    private static final Unsafe U = Unsafe.getUnsafe();
6340      private static final long SIZECTL;
6341      private static final long TRANSFERINDEX;
6342      private static final long BASECOUNT;
6343      private static final long CELLSBUSY;
6344      private static final long CELLVALUE;
6345 <    private static final long ABASE;
6345 >    private static final int ABASE;
6346      private static final int ASHIFT;
6347  
6348      static {
6349          try {
6262            U = sun.misc.Unsafe.getUnsafe();
6263            Class<?> k = ConcurrentHashMap.class;
6350              SIZECTL = U.objectFieldOffset
6351 <                (k.getDeclaredField("sizeCtl"));
6351 >                (ConcurrentHashMap.class.getDeclaredField("sizeCtl"));
6352              TRANSFERINDEX = U.objectFieldOffset
6353 <                (k.getDeclaredField("transferIndex"));
6353 >                (ConcurrentHashMap.class.getDeclaredField("transferIndex"));
6354              BASECOUNT = U.objectFieldOffset
6355 <                (k.getDeclaredField("baseCount"));
6355 >                (ConcurrentHashMap.class.getDeclaredField("baseCount"));
6356              CELLSBUSY = U.objectFieldOffset
6357 <                (k.getDeclaredField("cellsBusy"));
6358 <            Class<?> ck = CounterCell.class;
6357 >                (ConcurrentHashMap.class.getDeclaredField("cellsBusy"));
6358 >
6359              CELLVALUE = U.objectFieldOffset
6360 <                (ck.getDeclaredField("value"));
6361 <            Class<?> ak = Node[].class;
6362 <            ABASE = U.arrayBaseOffset(ak);
6363 <            int scale = U.arrayIndexScale(ak);
6360 >                (CounterCell.class.getDeclaredField("value"));
6361 >
6362 >            ABASE = U.arrayBaseOffset(Node[].class);
6363 >            int scale = U.arrayIndexScale(Node[].class);
6364              if ((scale & (scale - 1)) != 0)
6365 <                throw new Error("data type scale not a power of two");
6365 >                throw new Error("array index scale not a power of two");
6366              ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
6367 <        } catch (Exception e) {
6367 >        } catch (ReflectiveOperationException e) {
6368              throw new Error(e);
6369          }
6370 +
6371 +        // Reduce the risk of rare disastrous classloading in first call to
6372 +        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
6373 +        Class<?> ensureLoaded = LockSupport.class;
6374      }
6375   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines