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.257 by jsr166, Tue Jun 3 23:49:57 2014 UTC vs.
Revision 1.278 by jsr166, Sat Sep 12 21:55:08 2015 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 124 | Line 121 | import java.util.stream.Stream;
121   * being concurrently updated by other threads; for example, when
122   * computing a snapshot summary of the values in a shared registry.
123   * There are three kinds of operation, each with four forms, accepting
124 < * functions with Keys, Values, Entries, and (Key, Value) arguments
125 < * and/or return values. Because the elements of a ConcurrentHashMap
126 < * are not ordered in any particular way, and may be processed in
127 < * different orders in different parallel executions, the correctness
128 < * of supplied functions should not depend on any ordering, or on any
129 < * other objects or values that may transiently change while
130 < * computation is in progress; and except for forEach actions, should
131 < * ideally be side-effect-free. Bulk operations on {@link java.util.Map.Entry}
132 < * objects do not support method {@code setValue}.
124 > * functions with keys, values, entries, and (key, value) pairs as
125 > * arguments and/or return values. Because the elements of a
126 > * ConcurrentHashMap are not ordered in any particular way, and may be
127 > * processed in different orders in different parallel executions, the
128 > * correctness of supplied functions should not depend on any
129 > * ordering, or on any other objects or values that may transiently
130 > * change while computation is in progress; and except for forEach
131 > * actions, should ideally be side-effect-free. Bulk operations on
132 > * {@link java.util.Map.Entry} objects do not support method {@code
133 > * setValue}.
134   *
135   * <ul>
136   * <li> forEach: Perform a given action on each element.
# Line 451 | 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 600 | Line 598 | public class ConcurrentHashMap<K,V> exte
598              this.next = next;
599          }
600  
601 <        public final K getKey()       { return key; }
602 <        public final V getValue()     { return val; }
603 <        public final int hashCode()   { return key.hashCode() ^ val.hashCode(); }
604 <        public final String toString(){ return key + "=" + val; }
601 >        public final K getKey()     { return key; }
602 >        public final V getValue()   { return val; }
603 >        public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
604 >        public final String toString() {
605 >            return Helpers.mapEntryToString(key, val);
606 >        }
607          public final V setValue(V value) {
608              throw new UnsupportedOperationException();
609          }
# Line 1027 | Line 1027 | public class ConcurrentHashMap<K,V> exte
1027                                      p.val = value;
1028                              }
1029                          }
1030 +                        else if (f instanceof ReservationNode)
1031 +                            throw new IllegalStateException("Recursive update");
1032                      }
1033                  }
1034                  if (binCount != 0) {
# Line 1129 | Line 1131 | public class ConcurrentHashMap<K,V> exte
1131                                  }
1132                              }
1133                          }
1134 +                        else if (f instanceof ReservationNode)
1135 +                            throw new IllegalStateException("Recursive update");
1136                      }
1137                  }
1138                  if (validated) {
# Line 1371 | Line 1375 | public class ConcurrentHashMap<K,V> exte
1375              new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
1376          for (int i = 0; i < segments.length; ++i)
1377              segments[i] = new Segment<K,V>(LOAD_FACTOR);
1378 <        s.putFields().put("segments", segments);
1379 <        s.putFields().put("segmentShift", segmentShift);
1380 <        s.putFields().put("segmentMask", segmentMask);
1378 >        java.io.ObjectOutputStream.PutField streamFields = s.putFields();
1379 >        streamFields.put("segments", segments);
1380 >        streamFields.put("segmentShift", segmentShift);
1381 >        streamFields.put("segmentMask", segmentMask);
1382          s.writeFields();
1383  
1384          Node<K,V>[] t;
# Line 1590 | Line 1595 | public class ConcurrentHashMap<K,V> exte
1595      }
1596  
1597      /**
1598 +     * Helper method for EntrySetView.removeIf
1599 +     */
1600 +    boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
1601 +        if (function == null) throw new NullPointerException();
1602 +        Node<K,V>[] t;
1603 +        boolean removed = false;
1604 +        if ((t = table) != null) {
1605 +            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
1606 +            for (Node<K,V> p; (p = it.advance()) != null; ) {
1607 +                K k = p.key;
1608 +                V v = p.val;
1609 +                Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
1610 +                if (function.test(e) && replaceNode(k, null, v) != null)
1611 +                    removed = true;
1612 +            }
1613 +        }
1614 +        return removed;
1615 +    }
1616 +
1617 +    /**
1618 +     * Helper method for ValuesView.removeIf
1619 +     */
1620 +    boolean removeValueIf(Predicate<? super V> function) {
1621 +        if (function == null) throw new NullPointerException();
1622 +        Node<K,V>[] t;
1623 +        boolean removed = false;
1624 +        if ((t = table) != null) {
1625 +            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
1626 +            for (Node<K,V> p; (p = it.advance()) != null; ) {
1627 +                K k = p.key;
1628 +                V v = p.val;
1629 +                if (function.test(v) && replaceNode(k, null, v) != null)
1630 +                    removed = true;
1631 +            }
1632 +        }
1633 +        return removed;
1634 +    }
1635 +
1636 +    /**
1637       * If the specified key is not already associated with a value,
1638       * attempts to compute its value using the given mapping function
1639       * and enters it into this map unless {@code null}.  The entire
# Line 1647 | Line 1691 | public class ConcurrentHashMap<K,V> exte
1691                          if (fh >= 0) {
1692                              binCount = 1;
1693                              for (Node<K,V> e = f;; ++binCount) {
1694 <                                K ek; V ev;
1694 >                                K ek;
1695                                  if (e.hash == h &&
1696                                      ((ek = e.key) == key ||
1697                                       (ek != null && key.equals(ek)))) {
# Line 1657 | Line 1701 | public class ConcurrentHashMap<K,V> exte
1701                                  Node<K,V> pred = e;
1702                                  if ((e = e.next) == null) {
1703                                      if ((val = mappingFunction.apply(key)) != null) {
1704 +                                        if (pred.next != null)
1705 +                                            throw new IllegalStateException("Recursive update");
1706                                          added = true;
1707                                          pred.next = new Node<K,V>(h, key, val, null);
1708                                      }
# Line 1676 | Line 1722 | public class ConcurrentHashMap<K,V> exte
1722                                  t.putTreeVal(h, key, val);
1723                              }
1724                          }
1725 +                        else if (f instanceof ReservationNode)
1726 +                            throw new IllegalStateException("Recursive update");
1727                      }
1728                  }
1729                  if (binCount != 0) {
# Line 1771 | Line 1819 | public class ConcurrentHashMap<K,V> exte
1819                                  }
1820                              }
1821                          }
1822 +                        else if (f instanceof ReservationNode)
1823 +                            throw new IllegalStateException("Recursive update");
1824                      }
1825                  }
1826                  if (binCount != 0)
# Line 1862 | Line 1912 | public class ConcurrentHashMap<K,V> exte
1912                                  if ((e = e.next) == null) {
1913                                      val = remappingFunction.apply(key, null);
1914                                      if (val != null) {
1915 +                                        if (pred.next != null)
1916 +                                            throw new IllegalStateException("Recursive update");
1917                                          delta = 1;
1918                                          pred.next =
1919                                              new Node<K,V>(h, key, val, null);
# Line 1894 | Line 1946 | public class ConcurrentHashMap<K,V> exte
1946                                      setTabAt(tab, i, untreeify(t.first));
1947                              }
1948                          }
1949 +                        else if (f instanceof ReservationNode)
1950 +                            throw new IllegalStateException("Recursive update");
1951                      }
1952                  }
1953                  if (binCount != 0) {
# Line 2003 | Line 2057 | public class ConcurrentHashMap<K,V> exte
2057                                      setTabAt(tab, i, untreeify(t.first));
2058                              }
2059                          }
2060 +                        else if (f instanceof ReservationNode)
2061 +                            throw new IllegalStateException("Recursive update");
2062                      }
2063                  }
2064                  if (binCount != 0) {
# Line 2020 | Line 2076 | public class ConcurrentHashMap<K,V> exte
2076      // Hashtable legacy methods
2077  
2078      /**
2079 <     * Legacy method testing if some key maps into the specified value
2024 <     * in this table.
2079 >     * Tests if some key maps into the specified value in this table.
2080       *
2081 <     * @deprecated This method is identical in functionality to
2081 >     * <p>Note that this method is identical in functionality to
2082       * {@link #containsValue(Object)}, and exists solely to ensure
2083       * full compatibility with class {@link java.util.Hashtable},
2084 <     * which supported this method prior to introduction of the
2085 <     * Java Collections framework.
2084 >     * which supported this method prior to introduction of the Java
2085 >     * Collections Framework.
2086       *
2087       * @param  value a value to search for
2088       * @return {@code true} if and only if some key maps to the
# Line 2036 | Line 2091 | public class ConcurrentHashMap<K,V> exte
2091       *         {@code false} otherwise
2092       * @throws NullPointerException if the specified value is null
2093       */
2039    @Deprecated
2094      public boolean contains(Object value) {
2095          return containsValue(value);
2096      }
# Line 2318 | Line 2372 | public class ConcurrentHashMap<K,V> exte
2372                  break;
2373              else if (tab == table) {
2374                  int rs = resizeStamp(n);
2375 <                if (sc < 0) {
2376 <                    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))
2375 >                if (U.compareAndSwapInt(this, SIZECTL, sc,
2376 >                                        (rs << RESIZE_STAMP_SHIFT) + 2))
2377                      transfer(tab, null);
2378              }
2379          }
# Line 2583 | Line 2628 | public class ConcurrentHashMap<K,V> exte
2628       * too small, in which case resizes instead.
2629       */
2630      private final void treeifyBin(Node<K,V>[] tab, int index) {
2631 <        Node<K,V> b; int n, sc;
2631 >        Node<K,V> b; int n;
2632          if (tab != null) {
2633              if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
2634                  tryPresize(n << 1);
# Line 2746 | Line 2791 | public class ConcurrentHashMap<K,V> exte
2791                                    (kc = comparableClassFor(k)) == null) ||
2792                                   (dir = compareComparables(kc, k, pk)) == 0)
2793                              dir = tieBreakOrder(k, pk);
2794 <                            TreeNode<K,V> xp = p;
2794 >                        TreeNode<K,V> xp = p;
2795                          if ((p = (dir <= 0) ? p.left : p.right) == null) {
2796                              x.parent = xp;
2797                              if (dir <= 0)
# Line 3214 | Line 3259 | public class ConcurrentHashMap<K,V> exte
3259              return true;
3260          }
3261  
3262 <        private static final sun.misc.Unsafe U;
3262 >        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
3263          private static final long LOCKSTATE;
3264          static {
3265              try {
3221                U = sun.misc.Unsafe.getUnsafe();
3222                Class<?> k = TreeBin.class;
3266                  LOCKSTATE = U.objectFieldOffset
3267 <                    (k.getDeclaredField("lockState"));
3268 <            } catch (Exception e) {
3267 >                    (TreeBin.class.getDeclaredField("lockState"));
3268 >            } catch (ReflectiveOperationException e) {
3269                  throw new Error(e);
3270              }
3271          }
# Line 3451 | Line 3494 | public class ConcurrentHashMap<K,V> exte
3494          public K getKey()        { return key; }
3495          public V getValue()      { return val; }
3496          public int hashCode()    { return key.hashCode() ^ val.hashCode(); }
3497 <        public String toString() { return key + "=" + val; }
3497 >        public String toString() {
3498 >            return Helpers.mapEntryToString(key, val);
3499 >        }
3500  
3501          public boolean equals(Object o) {
3502              Object k, v; Map.Entry<?,?> e;
# Line 4664 | Line 4709 | public class ConcurrentHashMap<K,V> exte
4709              throw new UnsupportedOperationException();
4710          }
4711  
4712 +        public boolean removeIf(Predicate<? super V> filter) {
4713 +            return map.removeValueIf(filter);
4714 +        }
4715 +
4716          public Spliterator<V> spliterator() {
4717              Node<K,V>[] t;
4718              ConcurrentHashMap<K,V> m = map;
# Line 4733 | Line 4782 | public class ConcurrentHashMap<K,V> exte
4782              return added;
4783          }
4784  
4785 +        public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
4786 +            return map.removeEntryIf(filter);
4787 +        }
4788 +
4789          public final int hashCode() {
4790              int h = 0;
4791              Node<K,V>[] t;
# Line 6249 | Line 6302 | public class ConcurrentHashMap<K,V> exte
6302      }
6303  
6304      // Unsafe mechanics
6305 <    private static final sun.misc.Unsafe U;
6305 >    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
6306      private static final long SIZECTL;
6307      private static final long TRANSFERINDEX;
6308      private static final long BASECOUNT;
6309      private static final long CELLSBUSY;
6310      private static final long CELLVALUE;
6311 <    private static final long ABASE;
6311 >    private static final int ABASE;
6312      private static final int ASHIFT;
6313  
6314      static {
6315          try {
6263            U = sun.misc.Unsafe.getUnsafe();
6264            Class<?> k = ConcurrentHashMap.class;
6316              SIZECTL = U.objectFieldOffset
6317 <                (k.getDeclaredField("sizeCtl"));
6317 >                (ConcurrentHashMap.class.getDeclaredField("sizeCtl"));
6318              TRANSFERINDEX = U.objectFieldOffset
6319 <                (k.getDeclaredField("transferIndex"));
6319 >                (ConcurrentHashMap.class.getDeclaredField("transferIndex"));
6320              BASECOUNT = U.objectFieldOffset
6321 <                (k.getDeclaredField("baseCount"));
6321 >                (ConcurrentHashMap.class.getDeclaredField("baseCount"));
6322              CELLSBUSY = U.objectFieldOffset
6323 <                (k.getDeclaredField("cellsBusy"));
6324 <            Class<?> ck = CounterCell.class;
6323 >                (ConcurrentHashMap.class.getDeclaredField("cellsBusy"));
6324 >
6325              CELLVALUE = U.objectFieldOffset
6326 <                (ck.getDeclaredField("value"));
6327 <            Class<?> ak = Node[].class;
6328 <            ABASE = U.arrayBaseOffset(ak);
6329 <            int scale = U.arrayIndexScale(ak);
6326 >                (CounterCell.class.getDeclaredField("value"));
6327 >
6328 >            ABASE = U.arrayBaseOffset(Node[].class);
6329 >            int scale = U.arrayIndexScale(Node[].class);
6330              if ((scale & (scale - 1)) != 0)
6331 <                throw new Error("data type scale not a power of two");
6331 >                throw new Error("array index scale not a power of two");
6332              ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
6333 <        } catch (Exception e) {
6333 >        } catch (ReflectiveOperationException e) {
6334              throw new Error(e);
6335          }
6336 +
6337 +        // Reduce the risk of rare disastrous classloading in first call to
6338 +        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
6339 +        Class<?> ensureLoaded = LockSupport.class;
6340      }
6341   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines