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}/java/util/package-summary.html#CollectionsFramework"> |
227 |
> |
* <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework"> |
228 |
|
* Java Collections Framework</a>. |
229 |
|
* |
230 |
|
* @since 1.5 |
356 |
|
* cases where old nodes can be reused because their next fields |
357 |
|
* won't change. On average, only about one-sixth of them need |
358 |
|
* cloning when a table doubles. The nodes they replace will be |
359 |
< |
* garbage collectable as soon as they are no longer referenced by |
359 |
> |
* garbage collectible as soon as they are no longer referenced by |
360 |
|
* any reader thread that may be in the midst of concurrently |
361 |
|
* traversing table. Upon transfer, the old table bin contains |
362 |
|
* only a special forwarding node (with hash field "MOVED") that |
673 |
|
* See Hackers Delight, sec 3.2 |
674 |
|
*/ |
675 |
|
private static final int tableSizeFor(int c) { |
676 |
< |
int n = c - 1; |
677 |
< |
n |= n >>> 1; |
678 |
< |
n |= n >>> 2; |
679 |
< |
n |= n >>> 4; |
680 |
< |
n |= n >>> 8; |
681 |
< |
n |= n >>> 16; |
676 |
> |
int n = -1 >>> Integer.numberOfLeadingZeros(c - 1); |
677 |
|
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; |
678 |
|
} |
679 |
|
|
810 |
|
* elements is negative |
811 |
|
*/ |
812 |
|
public ConcurrentHashMap(int initialCapacity) { |
813 |
< |
if (initialCapacity < 0) |
819 |
< |
throw new IllegalArgumentException(); |
820 |
< |
int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? |
821 |
< |
MAXIMUM_CAPACITY : |
822 |
< |
tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)); |
823 |
< |
this.sizeCtl = cap; |
813 |
> |
this(initialCapacity, LOAD_FACTOR, 1); |
814 |
|
} |
815 |
|
|
816 |
|
/** |
844 |
|
|
845 |
|
/** |
846 |
|
* Creates a new, empty map with an initial table size based on |
847 |
< |
* the given number of elements ({@code initialCapacity}), table |
848 |
< |
* density ({@code loadFactor}), and number of concurrently |
847 |
> |
* the given number of elements ({@code initialCapacity}), initial |
848 |
> |
* table density ({@code loadFactor}), and number of concurrently |
849 |
|
* updating threads ({@code concurrencyLevel}). |
850 |
|
* |
851 |
|
* @param initialCapacity the initial capacity. The implementation |
1434 |
|
if (size == 0L) |
1435 |
|
sizeCtl = 0; |
1436 |
|
else { |
1437 |
< |
int n; |
1438 |
< |
if (size >= (long)(MAXIMUM_CAPACITY >>> 1)) |
1439 |
< |
n = MAXIMUM_CAPACITY; |
1450 |
< |
else { |
1451 |
< |
int sz = (int)size; |
1452 |
< |
n = tableSizeFor(sz + (sz >>> 1) + 1); |
1453 |
< |
} |
1437 |
> |
long ts = (long)(1.0 + size / LOAD_FACTOR); |
1438 |
> |
int n = (ts >= (long)MAXIMUM_CAPACITY) ? |
1439 |
> |
MAXIMUM_CAPACITY : tableSizeFor((int)ts); |
1440 |
|
@SuppressWarnings("unchecked") |
1441 |
|
Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n]; |
1442 |
|
int mask = n - 1; |
2305 |
|
Node<K,V>[] tab, nt; int n, sc; |
2306 |
|
while (s >= (long)(sc = sizeCtl) && (tab = table) != null && |
2307 |
|
(n = tab.length) < MAXIMUM_CAPACITY) { |
2308 |
< |
int rs = resizeStamp(n); |
2308 |
> |
int rs = resizeStamp(n) << RESIZE_STAMP_SHIFT; |
2309 |
|
if (sc < 0) { |
2310 |
< |
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || |
2311 |
< |
sc == rs + MAX_RESIZERS || (nt = nextTable) == null || |
2326 |
< |
transferIndex <= 0) |
2310 |
> |
if (sc == rs + MAX_RESIZERS || sc == rs + 1 || |
2311 |
> |
(nt = nextTable) == null || transferIndex <= 0) |
2312 |
|
break; |
2313 |
|
if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1)) |
2314 |
|
transfer(tab, nt); |
2315 |
|
} |
2316 |
< |
else if (U.compareAndSetInt(this, SIZECTL, sc, |
2332 |
< |
(rs << RESIZE_STAMP_SHIFT) + 2)) |
2316 |
> |
else if (U.compareAndSetInt(this, SIZECTL, sc, rs + 2)) |
2317 |
|
transfer(tab, null); |
2318 |
|
s = sumCount(); |
2319 |
|
} |
2327 |
|
Node<K,V>[] nextTab; int sc; |
2328 |
|
if (tab != null && (f instanceof ForwardingNode) && |
2329 |
|
(nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) { |
2330 |
< |
int rs = resizeStamp(tab.length); |
2330 |
> |
int rs = resizeStamp(tab.length) << RESIZE_STAMP_SHIFT; |
2331 |
|
while (nextTab == nextTable && table == tab && |
2332 |
|
(sc = sizeCtl) < 0) { |
2333 |
< |
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || |
2334 |
< |
sc == rs + MAX_RESIZERS || transferIndex <= 0) |
2333 |
> |
if (sc == rs + MAX_RESIZERS || sc == rs + 1 || |
2334 |
> |
transferIndex <= 0) |
2335 |
|
break; |
2336 |
|
if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1)) { |
2337 |
|
transfer(tab, nextTab); |
2511 |
|
setTabAt(tab, i, fwd); |
2512 |
|
advance = true; |
2513 |
|
} |
2514 |
+ |
else if (f instanceof ReservationNode) |
2515 |
+ |
throw new IllegalStateException("Recursive update"); |
2516 |
|
} |
2517 |
|
} |
2518 |
|
} |
3258 |
|
} |
3259 |
|
|
3260 |
|
private static final Unsafe U = Unsafe.getUnsafe(); |
3261 |
< |
private static final long LOCKSTATE; |
3262 |
< |
static { |
3277 |
< |
try { |
3278 |
< |
LOCKSTATE = U.objectFieldOffset |
3279 |
< |
(TreeBin.class.getDeclaredField("lockState")); |
3280 |
< |
} catch (ReflectiveOperationException e) { |
3281 |
< |
throw new Error(e); |
3282 |
< |
} |
3283 |
< |
} |
3261 |
> |
private static final long LOCKSTATE |
3262 |
> |
= U.objectFieldOffset(TreeBin.class, "lockState"); |
3263 |
|
} |
3264 |
|
|
3265 |
|
/* ----------------Table Traversal -------------- */ |
6325 |
|
private static final int ASHIFT; |
6326 |
|
|
6327 |
|
static { |
6328 |
< |
try { |
6329 |
< |
SIZECTL = U.objectFieldOffset |
6330 |
< |
(ConcurrentHashMap.class.getDeclaredField("sizeCtl")); |
6331 |
< |
TRANSFERINDEX = U.objectFieldOffset |
6332 |
< |
(ConcurrentHashMap.class.getDeclaredField("transferIndex")); |
6333 |
< |
BASECOUNT = U.objectFieldOffset |
6334 |
< |
(ConcurrentHashMap.class.getDeclaredField("baseCount")); |
6335 |
< |
CELLSBUSY = U.objectFieldOffset |
6336 |
< |
(ConcurrentHashMap.class.getDeclaredField("cellsBusy")); |
6337 |
< |
|
6338 |
< |
CELLVALUE = U.objectFieldOffset |
6339 |
< |
(CounterCell.class.getDeclaredField("value")); |
6340 |
< |
|
6341 |
< |
ABASE = U.arrayBaseOffset(Node[].class); |
6342 |
< |
int scale = U.arrayIndexScale(Node[].class); |
6343 |
< |
if ((scale & (scale - 1)) != 0) |
6344 |
< |
throw new Error("array index scale not a power of two"); |
6366 |
< |
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); |
6367 |
< |
} catch (ReflectiveOperationException e) { |
6368 |
< |
throw new Error(e); |
6369 |
< |
} |
6328 |
> |
SIZECTL = U.objectFieldOffset |
6329 |
> |
(ConcurrentHashMap.class, "sizeCtl"); |
6330 |
> |
TRANSFERINDEX = U.objectFieldOffset |
6331 |
> |
(ConcurrentHashMap.class, "transferIndex"); |
6332 |
> |
BASECOUNT = U.objectFieldOffset |
6333 |
> |
(ConcurrentHashMap.class, "baseCount"); |
6334 |
> |
CELLSBUSY = U.objectFieldOffset |
6335 |
> |
(ConcurrentHashMap.class, "cellsBusy"); |
6336 |
> |
|
6337 |
> |
CELLVALUE = U.objectFieldOffset |
6338 |
> |
(CounterCell.class, "value"); |
6339 |
> |
|
6340 |
> |
ABASE = U.arrayBaseOffset(Node[].class); |
6341 |
> |
int scale = U.arrayIndexScale(Node[].class); |
6342 |
> |
if ((scale & (scale - 1)) != 0) |
6343 |
> |
throw new ExceptionInInitializerError("array index scale not a power of two"); |
6344 |
> |
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); |
6345 |
|
|
6346 |
|
// Reduce the risk of rare disastrous classloading in first call to |
6347 |
|
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773 |
6348 |
|
Class<?> ensureLoaded = LockSupport.class; |
6349 |
+ |
|
6350 |
+ |
// Eager class load observed to help JIT during startup |
6351 |
+ |
ensureLoaded = ReservationNode.class; |
6352 |
|
} |
6353 |
|
} |