10 |
|
/** |
11 |
|
* A package-local class holding common representation and mechanics |
12 |
|
* for classes supporting dynamic striping on 64bit values. The class |
13 |
< |
* extends Number so that concrete subclasses can publicly do so. |
13 |
> |
* extends Number so that concrete subclasses must publicly do so. |
14 |
|
*/ |
15 |
|
abstract class Striped64 extends Number { |
16 |
|
/* |
40 |
|
* |
41 |
|
* A single spinlock ("busy") is used for initializing and |
42 |
|
* resizing the table, as well as populating slots with new Cells. |
43 |
< |
* There is no need for a blocking lock: When the lock is not |
43 |
> |
* There is no need for a blocking lock; when the lock is not |
44 |
|
* available, threads try other slots (or the base). During these |
45 |
|
* retries, there is increased contention and reduced locality, |
46 |
|
* which is still better than alternatives. |
77 |
|
*/ |
78 |
|
|
79 |
|
/** |
80 |
< |
* Padded variant of AtomicLong supporting only raw accesses plus |
81 |
< |
* CAS The value field is placed between pads, hoping that the JVM |
82 |
< |
* doesn't reorder them. |
80 |
> |
* Padded variant of AtomicLong supporting only raw accesses plus CAS. |
81 |
> |
* The value field is placed between pads, hoping that the JVM doesn't |
82 |
> |
* reorder them. |
83 |
|
* |
84 |
|
* JVM intrinsics note: It would be possible to use a release-only |
85 |
|
* form of CAS here, if it were provided. |
111 |
|
} |
112 |
|
|
113 |
|
/** |
114 |
< |
* Holder for the thread-local hash code. The code is initially |
115 |
< |
* random, but may be set to a different value upon collisions. |
114 |
> |
* ThreadLocal holding a single-slot int array holding hash code. |
115 |
> |
* Unlike the JDK8 version of this class, we use a suboptimal |
116 |
> |
* int[] representation to avoid introducing a new type that can |
117 |
> |
* impede class-unloading when ThreadLocals are not removed. |
118 |
|
*/ |
119 |
< |
static final class HashCode { |
118 |
< |
static final Random rng = new Random(); |
119 |
< |
int code; |
120 |
< |
HashCode() { |
121 |
< |
int h = rng.nextInt(); // Avoid zero to allow xorShift rehash |
122 |
< |
code = (h == 0) ? 1 : h; |
123 |
< |
} |
124 |
< |
} |
125 |
< |
|
126 |
< |
/** |
127 |
< |
* The corresponding ThreadLocal class |
128 |
< |
*/ |
129 |
< |
static final class ThreadHashCode extends ThreadLocal<HashCode> { |
130 |
< |
public HashCode initialValue() { return new HashCode(); } |
131 |
< |
} |
119 |
> |
static final ThreadLocal<int[]> threadHashCode = new ThreadLocal<int[]>(); |
120 |
|
|
121 |
|
/** |
122 |
< |
* Static per-thread hash codes. Shared across all instances to |
135 |
< |
* reduce ThreadLocal pollution and because adjustments due to |
136 |
< |
* collisions in one table are likely to be appropriate for |
137 |
< |
* others. |
122 |
> |
* Generator of new random hash codes |
123 |
|
*/ |
124 |
< |
static final ThreadHashCode threadHashCode = new ThreadHashCode(); |
124 |
> |
static final Random rng = new Random(); |
125 |
|
|
126 |
|
/** Number of CPUS, to place bound on table size */ |
127 |
|
static final int NCPU = Runtime.getRuntime().availableProcessors(); |
149 |
|
} |
150 |
|
|
151 |
|
/** |
152 |
< |
* CAS the base field |
152 |
> |
* CASes the base field. |
153 |
|
*/ |
154 |
|
final boolean casBase(long cmp, long val) { |
155 |
|
return UNSAFE.compareAndSwapLong(this, baseOffset, cmp, val); |
156 |
|
} |
157 |
|
|
158 |
|
/** |
159 |
< |
* CAS the busy field from 0 to 1 to acquire lock. |
159 |
> |
* CASes the busy field from 0 to 1 to acquire lock. |
160 |
|
*/ |
161 |
|
final boolean casBusy() { |
162 |
|
return UNSAFE.compareAndSwapInt(this, busyOffset, 0, 1); |
184 |
|
* @param hc the hash code holder |
185 |
|
* @param wasUncontended false if CAS failed before call |
186 |
|
*/ |
187 |
< |
final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { |
188 |
< |
int h = hc.code; |
187 |
> |
final void retryUpdate(long x, int[] hc, boolean wasUncontended) { |
188 |
> |
int h; |
189 |
> |
if (hc == null) { |
190 |
> |
threadHashCode.set(hc = new int[1]); // Initialize randomly |
191 |
> |
int r = rng.nextInt(); // Avoid zero to allow xorShift rehash |
192 |
> |
h = hc[0] = (r == 0) ? 1 : r; |
193 |
> |
} |
194 |
> |
else |
195 |
> |
h = hc[0]; |
196 |
|
boolean collide = false; // True if last slot nonempty |
197 |
|
for (;;) { |
198 |
|
Cell[] as; Cell a; int n; long v; |
245 |
|
h ^= h << 13; // Rehash |
246 |
|
h ^= h >>> 17; |
247 |
|
h ^= h << 5; |
248 |
+ |
hc[0] = h; // Record index for next time |
249 |
|
} |
250 |
|
else if (busy == 0 && cells == as && casBusy()) { |
251 |
|
boolean init = false; |
265 |
|
else if (casBase(v = base, fn(v, x))) |
266 |
|
break; // Fall back on using base |
267 |
|
} |
275 |
– |
hc.code = h; // Record index for next time |
268 |
|
} |
269 |
|
|
270 |
|
|
271 |
|
/** |
272 |
< |
* Set base and all cells to the given value |
272 |
> |
* Sets base and all cells to the given value. |
273 |
|
*/ |
274 |
|
final void internalReset(long initialValue) { |
275 |
|
Cell[] as = cells; |
311 |
|
private static sun.misc.Unsafe getUnsafe() { |
312 |
|
try { |
313 |
|
return sun.misc.Unsafe.getUnsafe(); |
314 |
< |
} catch (SecurityException se) { |
315 |
< |
try { |
316 |
< |
return java.security.AccessController.doPrivileged |
317 |
< |
(new java.security |
318 |
< |
.PrivilegedExceptionAction<sun.misc.Unsafe>() { |
319 |
< |
public sun.misc.Unsafe run() throws Exception { |
320 |
< |
java.lang.reflect.Field f = sun.misc |
321 |
< |
.Unsafe.class.getDeclaredField("theUnsafe"); |
322 |
< |
f.setAccessible(true); |
323 |
< |
return (sun.misc.Unsafe) f.get(null); |
324 |
< |
}}); |
325 |
< |
} catch (java.security.PrivilegedActionException e) { |
326 |
< |
throw new RuntimeException("Could not initialize intrinsics", |
327 |
< |
e.getCause()); |
328 |
< |
} |
314 |
> |
} catch (SecurityException tryReflectionInstead) {} |
315 |
> |
try { |
316 |
> |
return java.security.AccessController.doPrivileged |
317 |
> |
(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() { |
318 |
> |
public sun.misc.Unsafe run() throws Exception { |
319 |
> |
Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class; |
320 |
> |
for (java.lang.reflect.Field f : k.getDeclaredFields()) { |
321 |
> |
f.setAccessible(true); |
322 |
> |
Object x = f.get(null); |
323 |
> |
if (k.isInstance(x)) |
324 |
> |
return k.cast(x); |
325 |
> |
} |
326 |
> |
throw new NoSuchFieldError("the Unsafe"); |
327 |
> |
}}); |
328 |
> |
} catch (java.security.PrivilegedActionException e) { |
329 |
> |
throw new RuntimeException("Could not initialize intrinsics", |
330 |
> |
e.getCause()); |
331 |
|
} |
332 |
|
} |
339 |
– |
|
333 |
|
} |