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.271 by dl, Tue Apr 28 23:06:53 2015 UTC vs.
Revision 1.299 by jsr166, Sat Mar 18 19:19:04 2017 UTC

# Line 39 | 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 121 | 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 java.util.Map.Entry} objects do not support method {@code
134 > * setValue}.
135   *
136   * <ul>
137 < * <li> forEach: Perform a given action on each element.
137 > * <li>forEach: Performs a given action on each element.
138   * A variant form applies a given transformation on each element
139 < * before performing the action.</li>
139 > * before performing the action.
140   *
141 < * <li> search: Return the first available non-null result of
141 > * <li>search: Returns the first available non-null result of
142   * applying a given function on each element; skipping further
143 < * search when a result is found.</li>
143 > * search when a result is found.
144   *
145 < * <li> reduce: Accumulate each element.  The supplied reduction
145 > * <li>reduce: Accumulates each element.  The supplied reduction
146   * function cannot rely on ordering (more formally, it should be
147   * both associative and commutative).  There are five variants:
148   *
149   * <ul>
150   *
151 < * <li> Plain reductions. (There is not a form of this method for
151 > * <li>Plain reductions. (There is not a form of this method for
152   * (key, value) function arguments since there is no corresponding
153 < * return type.)</li>
153 > * return type.)
154   *
155 < * <li> Mapped reductions that accumulate the results of a given
156 < * function applied to each element.</li>
155 > * <li>Mapped reductions that accumulate the results of a given
156 > * function applied to each element.
157   *
158 < * <li> Reductions to scalar doubles, longs, and ints, using a
159 < * given basis value.</li>
158 > * <li>Reductions to scalar doubles, longs, and ints, using a
159 > * given basis value.
160   *
161   * </ul>
160 * </li>
162   * </ul>
163   *
164   * <p>These bulk operations accept a {@code parallelismThreshold}
# Line 268 | Line 269 | public class ConcurrentHashMap<K,V> exte
269       * Table accesses require volatile/atomic reads, writes, and
270       * CASes.  Because there is no other way to arrange this without
271       * adding further indirections, we use intrinsics
272 <     * (sun.misc.Unsafe) operations.
272 >     * (jdk.internal.misc.Unsafe) operations.
273       *
274       * We use the top (sign) bit of Node hash fields for control
275       * purposes -- it is available anyway because of addressing
# Line 448 | Line 449 | public class ConcurrentHashMap<K,V> exte
449       *
450       * Maintaining API and serialization compatibility with previous
451       * versions of this class introduces several oddities. Mainly: We
452 <     * leave untouched but unused constructor arguments refering to
452 >     * leave untouched but unused constructor arguments referring to
453       * concurrencyLevel. We accept a loadFactor constructor argument,
454       * but apply it only to initial table capacity (which is the only
455       * time that we can guarantee to honor it.) We also declare an
# Line 543 | Line 544 | public class ConcurrentHashMap<K,V> exte
544       * The number of bits used for generation stamp in sizeCtl.
545       * Must be at least 6 for 32bit arrays.
546       */
547 <    private static int RESIZE_STAMP_BITS = 16;
547 >    private static final int RESIZE_STAMP_BITS = 16;
548  
549      /**
550       * The maximum number of threads that can help resize.
# Line 567 | Line 568 | public class ConcurrentHashMap<K,V> exte
568      /** Number of CPUS, to place bounds on some sizings */
569      static final int NCPU = Runtime.getRuntime().availableProcessors();
570  
571 <    /** For serialization compatibility. */
571 >    /**
572 >     * Serialized pseudo-fields, provided only for jdk7 compatibility.
573 >     * @serialField segments Segment[]
574 >     *   The segments, each of which is a specialized hash table.
575 >     * @serialField segmentMask int
576 >     *   Mask value for indexing into segments. The upper bits of a
577 >     *   key's hash code are used to choose the segment.
578 >     * @serialField segmentShift int
579 >     *   Shift value for indexing within segments.
580 >     */
581      private static final ObjectStreamField[] serialPersistentFields = {
582          new ObjectStreamField("segments", Segment[].class),
583          new ObjectStreamField("segmentMask", Integer.TYPE),
584 <        new ObjectStreamField("segmentShift", Integer.TYPE)
584 >        new ObjectStreamField("segmentShift", Integer.TYPE),
585      };
586  
587      /* ---------------- Nodes -------------- */
# Line 590 | Line 600 | public class ConcurrentHashMap<K,V> exte
600          volatile V val;
601          volatile Node<K,V> next;
602  
603 <        Node(int hash, K key, V val, Node<K,V> next) {
603 >        Node(int hash, K key, V val) {
604              this.hash = hash;
605              this.key = key;
606              this.val = val;
607 +        }
608 +
609 +        Node(int hash, K key, V val, Node<K,V> next) {
610 +            this(hash, key, val);
611              this.next = next;
612          }
613  
# Line 705 | Line 719 | public class ConcurrentHashMap<K,V> exte
719      /* ---------------- Table element access -------------- */
720  
721      /*
722 <     * Volatile access methods are used for table elements as well as
722 >     * Atomic access methods are used for table elements as well as
723       * elements of in-progress next table while resizing.  All uses of
724       * the tab arguments must be null checked by callers.  All callers
725       * also paranoically precheck that tab's length is not zero (or an
# Line 715 | Line 729 | public class ConcurrentHashMap<K,V> exte
729       * errors by users, these checks must operate on local variables,
730       * which accounts for some odd-looking inline assignments below.
731       * Note that calls to setTabAt always occur within locked regions,
732 <     * and so in principle require only release ordering, not
719 <     * full volatile semantics, but are currently coded as volatile
720 <     * writes to be conservative.
732 >     * and so require only release ordering.
733       */
734  
735      @SuppressWarnings("unchecked")
736      static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
737 <        return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
737 >        return (Node<K,V>)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
738      }
739  
740      static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
# Line 731 | Line 743 | public class ConcurrentHashMap<K,V> exte
743      }
744  
745      static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
746 <        U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
746 >        U.putObjectRelease(tab, ((long)i << ASHIFT) + ABASE, v);
747      }
748  
749      /* ---------------- Fields -------------- */
# Line 982 | Line 994 | public class ConcurrentHashMap<K,V> exte
994          int hash = spread(key.hashCode());
995          int binCount = 0;
996          for (Node<K,V>[] tab = table;;) {
997 <            Node<K,V> f; int n, i, fh;
997 >            Node<K,V> f; int n, i, fh; K fk; V fv;
998              if (tab == null || (n = tab.length) == 0)
999                  tab = initTable();
1000              else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
1001 <                if (casTabAt(tab, i, null,
990 <                             new Node<K,V>(hash, key, value, null)))
1001 >                if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
1002                      break;                   // no lock when adding to empty bin
1003              }
1004              else if ((fh = f.hash) == MOVED)
1005                  tab = helpTransfer(tab, f);
1006 +            else if (onlyIfAbsent // check first node without acquiring lock
1007 +                     && fh == hash
1008 +                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
1009 +                     && (fv = f.val) != null)
1010 +                return fv;
1011              else {
1012                  V oldVal = null;
1013                  synchronized (f) {
# Line 1010 | Line 1026 | public class ConcurrentHashMap<K,V> exte
1026                                  }
1027                                  Node<K,V> pred = e;
1028                                  if ((e = e.next) == null) {
1029 <                                    pred.next = new Node<K,V>(hash, key,
1014 <                                                              value, null);
1029 >                                    pred.next = new Node<K,V>(hash, key, value);
1030                                      break;
1031                                  }
1032                              }
# Line 1202 | Line 1217 | public class ConcurrentHashMap<K,V> exte
1217       */
1218      public KeySetView<K,V> keySet() {
1219          KeySetView<K,V> ks;
1220 <        return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
1220 >        if ((ks = keySet) != null) return ks;
1221 >        return keySet = new KeySetView<K,V>(this, null);
1222      }
1223  
1224      /**
# Line 1225 | Line 1241 | public class ConcurrentHashMap<K,V> exte
1241       */
1242      public Collection<V> values() {
1243          ValuesView<K,V> vs;
1244 <        return (vs = values) != null ? vs : (values = new ValuesView<K,V>(this));
1244 >        if ((vs = values) != null) return vs;
1245 >        return values = new ValuesView<K,V>(this);
1246      }
1247  
1248      /**
# Line 1247 | Line 1264 | public class ConcurrentHashMap<K,V> exte
1264       */
1265      public Set<Map.Entry<K,V>> entrySet() {
1266          EntrySetView<K,V> es;
1267 <        return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K,V>(this));
1267 >        if ((es = entrySet) != null) return es;
1268 >        return entrySet = new EntrySetView<K,V>(this);
1269      }
1270  
1271      /**
# Line 1339 | Line 1357 | public class ConcurrentHashMap<K,V> exte
1357  
1358      /**
1359       * Stripped-down version of helper class used in previous version,
1360 <     * declared for the sake of serialization compatibility
1360 >     * declared for the sake of serialization compatibility.
1361       */
1362      static class Segment<K,V> extends ReentrantLock implements Serializable {
1363          private static final long serialVersionUID = 2249069246763182397L;
# Line 1353 | Line 1371 | public class ConcurrentHashMap<K,V> exte
1371       * @param s the stream
1372       * @throws java.io.IOException if an I/O error occurs
1373       * @serialData
1374 <     * the key (Object) and value (Object)
1375 <     * for each key-value mapping, followed by a null pair.
1374 >     * the serialized fields, followed by the key (Object) and value
1375 >     * (Object) for each key-value mapping, followed by a null pair.
1376       * The key-value mappings are emitted in no particular order.
1377       */
1378      private void writeObject(java.io.ObjectOutputStream s)
# Line 1390 | Line 1408 | public class ConcurrentHashMap<K,V> exte
1408          }
1409          s.writeObject(null);
1410          s.writeObject(null);
1393        segments = null; // throw away
1411      }
1412  
1413      /**
# Line 1594 | Line 1611 | public class ConcurrentHashMap<K,V> exte
1611      }
1612  
1613      /**
1614 <     * Helper method for EntrySet.removeIf
1614 >     * Helper method for EntrySetView.removeIf.
1615       */
1616 <    boolean removeEntryIf(Predicate<? super Entry<K, V>> function) {
1616 >    boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
1617          if (function == null) throw new NullPointerException();
1618          Node<K,V>[] t;
1619          boolean removed = false;
# Line 1614 | Line 1631 | public class ConcurrentHashMap<K,V> exte
1631      }
1632  
1633      /**
1634 +     * Helper method for ValuesView.removeIf.
1635 +     */
1636 +    boolean removeValueIf(Predicate<? super V> function) {
1637 +        if (function == null) throw new NullPointerException();
1638 +        Node<K,V>[] t;
1639 +        boolean removed = false;
1640 +        if ((t = table) != null) {
1641 +            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
1642 +            for (Node<K,V> p; (p = it.advance()) != null; ) {
1643 +                K k = p.key;
1644 +                V v = p.val;
1645 +                if (function.test(v) && replaceNode(k, null, v) != null)
1646 +                    removed = true;
1647 +            }
1648 +        }
1649 +        return removed;
1650 +    }
1651 +
1652 +    /**
1653       * If the specified key is not already associated with a value,
1654       * attempts to compute its value using the given mapping function
1655       * and enters it into this map unless {@code null}.  The entire
# Line 1642 | Line 1678 | public class ConcurrentHashMap<K,V> exte
1678          V val = null;
1679          int binCount = 0;
1680          for (Node<K,V>[] tab = table;;) {
1681 <            Node<K,V> f; int n, i, fh;
1681 >            Node<K,V> f; int n, i, fh; K fk; V fv;
1682              if (tab == null || (n = tab.length) == 0)
1683                  tab = initTable();
1684              else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
# Line 1653 | Line 1689 | public class ConcurrentHashMap<K,V> exte
1689                          Node<K,V> node = null;
1690                          try {
1691                              if ((val = mappingFunction.apply(key)) != null)
1692 <                                node = new Node<K,V>(h, key, val, null);
1692 >                                node = new Node<K,V>(h, key, val);
1693                          } finally {
1694                              setTabAt(tab, i, node);
1695                          }
# Line 1664 | Line 1700 | public class ConcurrentHashMap<K,V> exte
1700              }
1701              else if ((fh = f.hash) == MOVED)
1702                  tab = helpTransfer(tab, f);
1703 +            else if (fh == h    // check first node without acquiring lock
1704 +                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
1705 +                     && (fv = f.val) != null)
1706 +                return fv;
1707              else {
1708                  boolean added = false;
1709                  synchronized (f) {
# Line 1684 | Line 1724 | public class ConcurrentHashMap<K,V> exte
1724                                          if (pred.next != null)
1725                                              throw new IllegalStateException("Recursive update");
1726                                          added = true;
1727 <                                        pred.next = new Node<K,V>(h, key, val, null);
1727 >                                        pred.next = new Node<K,V>(h, key, val);
1728                                      }
1729                                      break;
1730                                  }
# Line 1853 | Line 1893 | public class ConcurrentHashMap<K,V> exte
1893                          try {
1894                              if ((val = remappingFunction.apply(key, null)) != null) {
1895                                  delta = 1;
1896 <                                node = new Node<K,V>(h, key, val, null);
1896 >                                node = new Node<K,V>(h, key, val);
1897                              }
1898                          } finally {
1899                              setTabAt(tab, i, node);
# Line 1895 | Line 1935 | public class ConcurrentHashMap<K,V> exte
1935                                          if (pred.next != null)
1936                                              throw new IllegalStateException("Recursive update");
1937                                          delta = 1;
1938 <                                        pred.next =
1899 <                                            new Node<K,V>(h, key, val, null);
1938 >                                        pred.next = new Node<K,V>(h, key, val);
1939                                      }
1940                                      break;
1941                                  }
# Line 1974 | Line 2013 | public class ConcurrentHashMap<K,V> exte
2013              if (tab == null || (n = tab.length) == 0)
2014                  tab = initTable();
2015              else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
2016 <                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value, null))) {
2016 >                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value))) {
2017                      delta = 1;
2018                      val = value;
2019                      break;
# Line 2009 | Line 2048 | public class ConcurrentHashMap<K,V> exte
2048                                  if ((e = e.next) == null) {
2049                                      delta = 1;
2050                                      val = value;
2051 <                                    pred.next =
2013 <                                        new Node<K,V>(h, key, val, null);
2051 >                                    pred.next = new Node<K,V>(h, key, val);
2052                                      break;
2053                                  }
2054                              }
# Line 2056 | Line 2094 | public class ConcurrentHashMap<K,V> exte
2094      // Hashtable legacy methods
2095  
2096      /**
2097 <     * Legacy method testing if some key maps into the specified value
2060 <     * in this table.
2097 >     * Tests if some key maps into the specified value in this table.
2098       *
2099 <     * @deprecated This method is identical in functionality to
2099 >     * <p>Note that this method is identical in functionality to
2100       * {@link #containsValue(Object)}, and exists solely to ensure
2101       * full compatibility with class {@link java.util.Hashtable},
2102       * which supported this method prior to introduction of the
2103 <     * Java Collections framework.
2103 >     * Java Collections Framework.
2104       *
2105       * @param  value a value to search for
2106       * @return {@code true} if and only if some key maps to the
# Line 2072 | Line 2109 | public class ConcurrentHashMap<K,V> exte
2109       *         {@code false} otherwise
2110       * @throws NullPointerException if the specified value is null
2111       */
2075    @Deprecated
2112      public boolean contains(Object value) {
2113          return containsValue(value);
2114      }
# Line 2173 | Line 2209 | public class ConcurrentHashMap<K,V> exte
2209      static final class ForwardingNode<K,V> extends Node<K,V> {
2210          final Node<K,V>[] nextTable;
2211          ForwardingNode(Node<K,V>[] tab) {
2212 <            super(MOVED, null, null, null);
2212 >            super(MOVED, null, null);
2213              this.nextTable = tab;
2214          }
2215  
# Line 2205 | Line 2241 | public class ConcurrentHashMap<K,V> exte
2241      }
2242  
2243      /**
2244 <     * A place-holder node used in computeIfAbsent and compute
2244 >     * A place-holder node used in computeIfAbsent and compute.
2245       */
2246      static final class ReservationNode<K,V> extends Node<K,V> {
2247          ReservationNode() {
2248 <            super(RESERVED, null, null, null);
2248 >            super(RESERVED, null, null);
2249          }
2250  
2251          Node<K,V> find(int h, Object k) {
# Line 2504 | Line 2540 | public class ConcurrentHashMap<K,V> exte
2540       * A padded cell for distributing counts.  Adapted from LongAdder
2541       * and Striped64.  See their internal docs for explanation.
2542       */
2543 <    @sun.misc.Contended static final class CounterCell {
2543 >    @jdk.internal.vm.annotation.Contended static final class CounterCell {
2544          volatile long value;
2545          CounterCell(long x) { value = x; }
2546      }
# Line 2636 | Line 2672 | public class ConcurrentHashMap<K,V> exte
2672      }
2673  
2674      /**
2675 <     * Returns a list on non-TreeNodes replacing those in given list.
2675 >     * Returns a list of non-TreeNodes replacing those in given list.
2676       */
2677      static <K,V> Node<K,V> untreeify(Node<K,V> b) {
2678          Node<K,V> hd = null, tl = null;
2679          for (Node<K,V> q = b; q != null; q = q.next) {
2680 <            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val, null);
2680 >            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val);
2681              if (tl == null)
2682                  hd = p;
2683              else
# Line 2654 | Line 2690 | public class ConcurrentHashMap<K,V> exte
2690      /* ---------------- TreeNodes -------------- */
2691  
2692      /**
2693 <     * Nodes for use in TreeBins
2693 >     * Nodes for use in TreeBins.
2694       */
2695      static final class TreeNode<K,V> extends Node<K,V> {
2696          TreeNode<K,V> parent;  // red-black tree links
# Line 2747 | Line 2783 | public class ConcurrentHashMap<K,V> exte
2783           * Creates bin with initial set of nodes headed by b.
2784           */
2785          TreeBin(TreeNode<K,V> b) {
2786 <            super(TREEBIN, null, null, null);
2786 >            super(TREEBIN, null, null);
2787              this.first = b;
2788              TreeNode<K,V> r = null;
2789              for (TreeNode<K,V> x = b, next; x != null; x = next) {
# Line 3217 | Line 3253 | public class ConcurrentHashMap<K,V> exte
3253          }
3254  
3255          /**
3256 <         * Recursive invariant check
3256 >         * Checks invariants recursively for the tree of Nodes rooted at t.
3257           */
3258          static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
3259              TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
# Line 3241 | Line 3277 | public class ConcurrentHashMap<K,V> exte
3277              return true;
3278          }
3279  
3280 <        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
3280 >        private static final Unsafe U = Unsafe.getUnsafe();
3281          private static final long LOCKSTATE;
3282          static {
3283              try {
# Line 3404 | Line 3440 | public class ConcurrentHashMap<K,V> exte
3440  
3441      static final class KeyIterator<K,V> extends BaseIterator<K,V>
3442          implements Iterator<K>, Enumeration<K> {
3443 <        KeyIterator(Node<K,V>[] tab, int index, int size, int limit,
3443 >        KeyIterator(Node<K,V>[] tab, int size, int index, int limit,
3444                      ConcurrentHashMap<K,V> map) {
3445 <            super(tab, index, size, limit, map);
3445 >            super(tab, size, index, limit, map);
3446          }
3447  
3448          public final K next() {
# Line 3424 | Line 3460 | public class ConcurrentHashMap<K,V> exte
3460  
3461      static final class ValueIterator<K,V> extends BaseIterator<K,V>
3462          implements Iterator<V>, Enumeration<V> {
3463 <        ValueIterator(Node<K,V>[] tab, int index, int size, int limit,
3463 >        ValueIterator(Node<K,V>[] tab, int size, int index, int limit,
3464                        ConcurrentHashMap<K,V> map) {
3465 <            super(tab, index, size, limit, map);
3465 >            super(tab, size, index, limit, map);
3466          }
3467  
3468          public final V next() {
# Line 3444 | Line 3480 | public class ConcurrentHashMap<K,V> exte
3480  
3481      static final class EntryIterator<K,V> extends BaseIterator<K,V>
3482          implements Iterator<Map.Entry<K,V>> {
3483 <        EntryIterator(Node<K,V>[] tab, int index, int size, int limit,
3483 >        EntryIterator(Node<K,V>[] tab, int size, int index, int limit,
3484                        ConcurrentHashMap<K,V> map) {
3485 <            super(tab, index, size, limit, map);
3485 >            super(tab, size, index, limit, map);
3486          }
3487  
3488          public final Map.Entry<K,V> next() {
# Line 3462 | Line 3498 | public class ConcurrentHashMap<K,V> exte
3498      }
3499  
3500      /**
3501 <     * Exported Entry for EntryIterator
3501 >     * Exported Entry for EntryIterator.
3502       */
3503      static final class MapEntry<K,V> implements Map.Entry<K,V> {
3504          final K key; // non-null
# Line 3515 | Line 3551 | public class ConcurrentHashMap<K,V> exte
3551              this.est = est;
3552          }
3553  
3554 <        public Spliterator<K> trySplit() {
3554 >        public KeySpliterator<K,V> trySplit() {
3555              int i, f, h;
3556              return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
3557                  new KeySpliterator<K,V>(tab, baseSize, baseLimit = h,
# Line 3554 | Line 3590 | public class ConcurrentHashMap<K,V> exte
3590              this.est = est;
3591          }
3592  
3593 <        public Spliterator<V> trySplit() {
3593 >        public ValueSpliterator<K,V> trySplit() {
3594              int i, f, h;
3595              return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
3596                  new ValueSpliterator<K,V>(tab, baseSize, baseLimit = h,
# Line 3594 | Line 3630 | public class ConcurrentHashMap<K,V> exte
3630              this.est = est;
3631          }
3632  
3633 <        public Spliterator<Map.Entry<K,V>> trySplit() {
3633 >        public EntrySpliterator<K,V> trySplit() {
3634              int i, f, h;
3635              return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
3636                  new EntrySpliterator<K,V>(tab, baseSize, baseLimit = h,
# Line 4406 | Line 4442 | public class ConcurrentHashMap<K,V> exte
4442          public abstract boolean contains(Object o);
4443          public abstract boolean remove(Object o);
4444  
4445 <        private static final String oomeMsg = "Required array size too large";
4445 >        private static final String OOME_MSG = "Required array size too large";
4446  
4447          public final Object[] toArray() {
4448              long sz = map.mappingCount();
4449              if (sz > MAX_ARRAY_SIZE)
4450 <                throw new OutOfMemoryError(oomeMsg);
4450 >                throw new OutOfMemoryError(OOME_MSG);
4451              int n = (int)sz;
4452              Object[] r = new Object[n];
4453              int i = 0;
4454              for (E e : this) {
4455                  if (i == n) {
4456                      if (n >= MAX_ARRAY_SIZE)
4457 <                        throw new OutOfMemoryError(oomeMsg);
4457 >                        throw new OutOfMemoryError(OOME_MSG);
4458                      if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
4459                          n = MAX_ARRAY_SIZE;
4460                      else
# Line 4434 | Line 4470 | public class ConcurrentHashMap<K,V> exte
4470          public final <T> T[] toArray(T[] a) {
4471              long sz = map.mappingCount();
4472              if (sz > MAX_ARRAY_SIZE)
4473 <                throw new OutOfMemoryError(oomeMsg);
4473 >                throw new OutOfMemoryError(OOME_MSG);
4474              int m = (int)sz;
4475              T[] r = (a.length >= m) ? a :
4476                  (T[])java.lang.reflect.Array
# Line 4444 | Line 4480 | public class ConcurrentHashMap<K,V> exte
4480              for (E e : this) {
4481                  if (i == n) {
4482                      if (n >= MAX_ARRAY_SIZE)
4483 <                        throw new OutOfMemoryError(oomeMsg);
4483 >                        throw new OutOfMemoryError(OOME_MSG);
4484                      if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
4485                          n = MAX_ARRAY_SIZE;
4486                      else
# Line 4497 | Line 4533 | public class ConcurrentHashMap<K,V> exte
4533              return true;
4534          }
4535  
4536 <        public final boolean removeAll(Collection<?> c) {
4536 >        public boolean removeAll(Collection<?> c) {
4537              if (c == null) throw new NullPointerException();
4538              boolean modified = false;
4539 <            for (Iterator<E> it = iterator(); it.hasNext();) {
4540 <                if (c.contains(it.next())) {
4541 <                    it.remove();
4542 <                    modified = true;
4539 >            // Use (c instanceof Set) as a hint that lookup in c is as
4540 >            // efficient as this view
4541 >            Node<K,V>[] t;
4542 >            if ((t = map.table) == null) {
4543 >                return false;
4544 >            } else if (c instanceof Set<?> && c.size() > t.length) {
4545 >                for (Iterator<?> it = iterator(); it.hasNext(); ) {
4546 >                    if (c.contains(it.next())) {
4547 >                        it.remove();
4548 >                        modified = true;
4549 >                    }
4550                  }
4551 +            } else {
4552 +                for (Object e : c)
4553 +                    modified |= remove(e);
4554              }
4555              return modified;
4556          }
# Line 4691 | Line 4737 | public class ConcurrentHashMap<K,V> exte
4737              throw new UnsupportedOperationException();
4738          }
4739  
4740 +        @Override public boolean removeAll(Collection<?> c) {
4741 +            if (c == null) throw new NullPointerException();
4742 +            boolean modified = false;
4743 +            for (Iterator<V> it = iterator(); it.hasNext();) {
4744 +                if (c.contains(it.next())) {
4745 +                    it.remove();
4746 +                    modified = true;
4747 +                }
4748 +            }
4749 +            return modified;
4750 +        }
4751 +
4752 +        public boolean removeIf(Predicate<? super V> filter) {
4753 +            return map.removeValueIf(filter);
4754 +        }
4755 +
4756          public Spliterator<V> spliterator() {
4757              Node<K,V>[] t;
4758              ConcurrentHashMap<K,V> m = map;
# Line 4760 | Line 4822 | public class ConcurrentHashMap<K,V> exte
4822              return added;
4823          }
4824  
4825 <        public boolean removeIf(Predicate<? super Entry<K, V>> filter) {
4825 >        public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
4826              return map.removeEntryIf(filter);
4827          }
4828  
# Line 4835 | Line 4897 | public class ConcurrentHashMap<K,V> exte
4897          }
4898  
4899          /**
4900 <         * Same as Traverser version
4900 >         * Same as Traverser version.
4901           */
4902          final Node<K,V> advance() {
4903              Node<K,V> e;
# Line 6280 | Line 6342 | public class ConcurrentHashMap<K,V> exte
6342      }
6343  
6344      // Unsafe mechanics
6345 <    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
6345 >    private static final Unsafe U = Unsafe.getUnsafe();
6346      private static final long SIZECTL;
6347      private static final long TRANSFERINDEX;
6348      private static final long BASECOUNT;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines