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; |
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; |
100 |
|
* mapped values are (perhaps transiently) not used or all take the |
101 |
|
* same mapping value. |
102 |
|
* |
103 |
< |
* <p>A ConcurrentHashMap can be used as scalable frequency map (a |
103 |
> |
* <p>A ConcurrentHashMap can be used as a scalable frequency map (a |
104 |
|
* form of histogram or multiset) by using {@link |
105 |
|
* java.util.concurrent.atomic.LongAdder} values and initializing via |
106 |
|
* {@link #computeIfAbsent computeIfAbsent}. For example, to add a count |
107 |
|
* to a {@code ConcurrentHashMap<String,LongAdder> freqs}, you can use |
108 |
< |
* {@code freqs.computeIfAbsent(k -> new LongAdder()).increment();} |
108 |
> |
* {@code freqs.computeIfAbsent(key, k -> new LongAdder()).increment();} |
109 |
|
* |
110 |
|
* <p>This class and its views and iterators implement all of the |
111 |
|
* <em>optional</em> methods of the {@link Map} and {@link Iterator} |
596 |
|
this.next = next; |
597 |
|
} |
598 |
|
|
599 |
< |
public final K getKey() { return key; } |
600 |
< |
public final V getValue() { return val; } |
601 |
< |
public final int hashCode() { return key.hashCode() ^ val.hashCode(); } |
602 |
< |
public final String toString(){ return key + "=" + val; } |
599 |
> |
public final K getKey() { return key; } |
600 |
> |
public final V getValue() { return val; } |
601 |
> |
public final String toString() { return key + "=" + val; } |
602 |
> |
public final int hashCode() { |
603 |
> |
return key.hashCode() ^ val.hashCode(); |
604 |
> |
} |
605 |
|
public final V setValue(V value) { |
606 |
|
throw new UnsupportedOperationException(); |
607 |
|
} |
1025 |
|
p.val = value; |
1026 |
|
} |
1027 |
|
} |
1028 |
+ |
else if (f instanceof ReservationNode) |
1029 |
+ |
throw new IllegalStateException("Recursive update"); |
1030 |
|
} |
1031 |
|
} |
1032 |
|
if (binCount != 0) { |
1129 |
|
} |
1130 |
|
} |
1131 |
|
} |
1132 |
+ |
else if (f instanceof ReservationNode) |
1133 |
+ |
throw new IllegalStateException("Recursive update"); |
1134 |
|
} |
1135 |
|
} |
1136 |
|
if (validated) { |
1649 |
|
if (fh >= 0) { |
1650 |
|
binCount = 1; |
1651 |
|
for (Node<K,V> e = f;; ++binCount) { |
1652 |
< |
K ek; V ev; |
1652 |
> |
K ek; |
1653 |
|
if (e.hash == h && |
1654 |
|
((ek = e.key) == key || |
1655 |
|
(ek != null && key.equals(ek)))) { |
1659 |
|
Node<K,V> pred = e; |
1660 |
|
if ((e = e.next) == null) { |
1661 |
|
if ((val = mappingFunction.apply(key)) != null) { |
1662 |
+ |
if (pred.next != null) |
1663 |
+ |
throw new IllegalStateException("Recursive update"); |
1664 |
|
added = true; |
1665 |
|
pred.next = new Node<K,V>(h, key, val, null); |
1666 |
|
} |
1680 |
|
t.putTreeVal(h, key, val); |
1681 |
|
} |
1682 |
|
} |
1683 |
+ |
else if (f instanceof ReservationNode) |
1684 |
+ |
throw new IllegalStateException("Recursive update"); |
1685 |
|
} |
1686 |
|
} |
1687 |
|
if (binCount != 0) { |
1777 |
|
} |
1778 |
|
} |
1779 |
|
} |
1780 |
+ |
else if (f instanceof ReservationNode) |
1781 |
+ |
throw new IllegalStateException("Recursive update"); |
1782 |
|
} |
1783 |
|
} |
1784 |
|
if (binCount != 0) |
1870 |
|
if ((e = e.next) == null) { |
1871 |
|
val = remappingFunction.apply(key, null); |
1872 |
|
if (val != null) { |
1873 |
+ |
if (pred.next != null) |
1874 |
+ |
throw new IllegalStateException("Recursive update"); |
1875 |
|
delta = 1; |
1876 |
|
pred.next = |
1877 |
|
new Node<K,V>(h, key, val, null); |
1904 |
|
setTabAt(tab, i, untreeify(t.first)); |
1905 |
|
} |
1906 |
|
} |
1907 |
+ |
else if (f instanceof ReservationNode) |
1908 |
+ |
throw new IllegalStateException("Recursive update"); |
1909 |
|
} |
1910 |
|
} |
1911 |
|
if (binCount != 0) { |
2015 |
|
setTabAt(tab, i, untreeify(t.first)); |
2016 |
|
} |
2017 |
|
} |
2018 |
+ |
else if (f instanceof ReservationNode) |
2019 |
+ |
throw new IllegalStateException("Recursive update"); |
2020 |
|
} |
2021 |
|
} |
2022 |
|
if (binCount != 0) { |
2202 |
|
* Must be negative when shifted left by RESIZE_STAMP_SHIFT. |
2203 |
|
*/ |
2204 |
|
static final int resizeStamp(int n) { |
2205 |
< |
return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1)); |
2205 |
> |
return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1)); |
2206 |
|
} |
2207 |
|
|
2208 |
|
/** |
2265 |
|
int rs = resizeStamp(n); |
2266 |
|
if (sc < 0) { |
2267 |
|
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || |
2268 |
< |
sc == rs + MAX_RESIZERS || (nt = nextTable) == null || |
2269 |
< |
transferIndex <= 0) |
2268 |
> |
sc == rs + MAX_RESIZERS || (nt = nextTable) == null || |
2269 |
> |
transferIndex <= 0) |
2270 |
|
break; |
2271 |
|
if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) |
2272 |
|
transfer(tab, nt); |
2273 |
|
} |
2274 |
|
else if (U.compareAndSwapInt(this, SIZECTL, sc, |
2275 |
< |
(rs << RESIZE_STAMP_SHIFT) + 2)) |
2275 |
> |
(rs << RESIZE_STAMP_SHIFT) + 2)) |
2276 |
|
transfer(tab, null); |
2277 |
|
s = sumCount(); |
2278 |
|
} |
2286 |
|
Node<K,V>[] nextTab; int sc; |
2287 |
|
if (tab != null && (f instanceof ForwardingNode) && |
2288 |
|
(nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) { |
2289 |
< |
int rs = resizeStamp(tab.length); |
2289 |
> |
int rs = resizeStamp(tab.length); |
2290 |
|
while (nextTab == nextTable && table == tab && |
2291 |
< |
(sc = sizeCtl) < 0) { |
2292 |
< |
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || |
2291 |
> |
(sc = sizeCtl) < 0) { |
2292 |
> |
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || |
2293 |
|
sc == rs + MAX_RESIZERS || transferIndex <= 0) |
2294 |
< |
break; |
2295 |
< |
if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) { |
2294 |
> |
break; |
2295 |
> |
if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) { |
2296 |
|
transfer(tab, nextTab); |
2297 |
|
break; |
2298 |
|
} |
2332 |
|
break; |
2333 |
|
else if (tab == table) { |
2334 |
|
int rs = resizeStamp(n); |
2335 |
< |
if (sc < 0) { |
2336 |
< |
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)) |
2335 |
> |
if (U.compareAndSwapInt(this, SIZECTL, sc, |
2336 |
> |
(rs << RESIZE_STAMP_SHIFT) + 2)) |
2337 |
|
transfer(tab, null); |
2338 |
|
} |
2339 |
|
} |
2391 |
|
return; |
2392 |
|
} |
2393 |
|
if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) { |
2394 |
< |
if ((sc - 2) != resizeStamp(n)) |
2394 |
> |
if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT) |
2395 |
|
return; |
2396 |
|
finishing = advance = true; |
2397 |
|
i = n; // recheck before commit |
2588 |
|
* too small, in which case resizes instead. |
2589 |
|
*/ |
2590 |
|
private final void treeifyBin(Node<K,V>[] tab, int index) { |
2591 |
< |
Node<K,V> b; int n, sc; |
2591 |
> |
Node<K,V> b; int n; |
2592 |
|
if (tab != null) { |
2593 |
|
if ((n = tab.length) < MIN_TREEIFY_CAPACITY) |
2594 |
|
tryPresize(n << 1); |
2658 |
|
final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) { |
2659 |
|
if (k != null) { |
2660 |
|
TreeNode<K,V> p = this; |
2661 |
< |
do { |
2661 |
> |
do { |
2662 |
|
int ph, dir; K pk; TreeNode<K,V> q; |
2663 |
|
TreeNode<K,V> pl = p.left, pr = p.right; |
2664 |
|
if ((ph = p.hash) > h) |
2751 |
|
(kc = comparableClassFor(k)) == null) || |
2752 |
|
(dir = compareComparables(kc, k, pk)) == 0) |
2753 |
|
dir = tieBreakOrder(k, pk); |
2754 |
< |
TreeNode<K,V> xp = p; |
2754 |
> |
TreeNode<K,V> xp = p; |
2755 |
|
if ((p = (dir <= 0) ? p.left : p.right) == null) { |
2756 |
|
x.parent = xp; |
2757 |
|
if (dir <= 0) |
2814 |
|
*/ |
2815 |
|
final Node<K,V> find(int h, Object k) { |
2816 |
|
if (k != null) { |
2817 |
< |
for (Node<K,V> e = first; e != null; e = e.next) { |
2817 |
> |
for (Node<K,V> e = first; e != null; ) { |
2818 |
|
int s; K ek; |
2819 |
|
if (((s = lockState) & (WAITER|WRITER)) != 0) { |
2820 |
|
if (e.hash == h && |
2821 |
|
((ek = e.key) == k || (ek != null && k.equals(ek)))) |
2822 |
|
return e; |
2823 |
+ |
e = e.next; |
2824 |
|
} |
2825 |
|
else if (U.compareAndSwapInt(this, LOCKSTATE, s, |
2826 |
|
s + READER)) { |
3104 |
|
|
3105 |
|
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root, |
3106 |
|
TreeNode<K,V> x) { |
3107 |
< |
for (TreeNode<K,V> xp, xpl, xpr;;) { |
3107 |
> |
for (TreeNode<K,V> xp, xpl, xpr;;) { |
3108 |
|
if (x == null || x == root) |
3109 |
|
return root; |
3110 |
|
else if ((xp = x.parent) == null) { |
3219 |
|
return true; |
3220 |
|
} |
3221 |
|
|
3222 |
< |
private static final sun.misc.Unsafe U; |
3222 |
> |
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); |
3223 |
|
private static final long LOCKSTATE; |
3224 |
|
static { |
3225 |
|
try { |
3220 |
– |
U = sun.misc.Unsafe.getUnsafe(); |
3221 |
– |
Class<?> k = TreeBin.class; |
3226 |
|
LOCKSTATE = U.objectFieldOffset |
3227 |
< |
(k.getDeclaredField("lockState")); |
3228 |
< |
} catch (Exception e) { |
3227 |
> |
(TreeBin.class.getDeclaredField("lockState")); |
3228 |
> |
} catch (ReflectiveOperationException e) { |
3229 |
|
throw new Error(e); |
3230 |
|
} |
3231 |
|
} |
6252 |
|
} |
6253 |
|
|
6254 |
|
// Unsafe mechanics |
6255 |
< |
private static final sun.misc.Unsafe U; |
6255 |
> |
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); |
6256 |
|
private static final long SIZECTL; |
6257 |
|
private static final long TRANSFERINDEX; |
6258 |
|
private static final long BASECOUNT; |
6259 |
|
private static final long CELLSBUSY; |
6260 |
|
private static final long CELLVALUE; |
6261 |
< |
private static final long ABASE; |
6261 |
> |
private static final int ABASE; |
6262 |
|
private static final int ASHIFT; |
6263 |
|
|
6264 |
|
static { |
6265 |
|
try { |
6262 |
– |
U = sun.misc.Unsafe.getUnsafe(); |
6263 |
– |
Class<?> k = ConcurrentHashMap.class; |
6266 |
|
SIZECTL = U.objectFieldOffset |
6267 |
< |
(k.getDeclaredField("sizeCtl")); |
6267 |
> |
(ConcurrentHashMap.class.getDeclaredField("sizeCtl")); |
6268 |
|
TRANSFERINDEX = U.objectFieldOffset |
6269 |
< |
(k.getDeclaredField("transferIndex")); |
6269 |
> |
(ConcurrentHashMap.class.getDeclaredField("transferIndex")); |
6270 |
|
BASECOUNT = U.objectFieldOffset |
6271 |
< |
(k.getDeclaredField("baseCount")); |
6271 |
> |
(ConcurrentHashMap.class.getDeclaredField("baseCount")); |
6272 |
|
CELLSBUSY = U.objectFieldOffset |
6273 |
< |
(k.getDeclaredField("cellsBusy")); |
6274 |
< |
Class<?> ck = CounterCell.class; |
6273 |
> |
(ConcurrentHashMap.class.getDeclaredField("cellsBusy")); |
6274 |
> |
|
6275 |
|
CELLVALUE = U.objectFieldOffset |
6276 |
< |
(ck.getDeclaredField("value")); |
6277 |
< |
Class<?> ak = Node[].class; |
6278 |
< |
ABASE = U.arrayBaseOffset(ak); |
6279 |
< |
int scale = U.arrayIndexScale(ak); |
6276 |
> |
(CounterCell.class.getDeclaredField("value")); |
6277 |
> |
|
6278 |
> |
ABASE = U.arrayBaseOffset(Node[].class); |
6279 |
> |
int scale = U.arrayIndexScale(Node[].class); |
6280 |
|
if ((scale & (scale - 1)) != 0) |
6281 |
< |
throw new Error("data type scale not a power of two"); |
6281 |
> |
throw new Error("array index scale not a power of two"); |
6282 |
|
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); |
6283 |
< |
} catch (Exception e) { |
6283 |
> |
} catch (ReflectiveOperationException e) { |
6284 |
|
throw new Error(e); |
6285 |
|
} |
6286 |
|
} |