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 |
< |
} |
119 |
> |
static final ThreadLocal<int[]> threadHashCode = new ThreadLocal<int[]>(); |
120 |
|
|
121 |
|
/** |
122 |
< |
* The corresponding ThreadLocal class |
122 |
> |
* Generator of new random hash codes |
123 |
|
*/ |
124 |
< |
static final class ThreadHashCode extends ThreadLocal<HashCode> { |
130 |
< |
public HashCode initialValue() { return new HashCode(); } |
131 |
< |
} |
132 |
< |
|
133 |
< |
/** |
134 |
< |
* 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. |
138 |
< |
*/ |
139 |
< |
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(); |
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 |
|
|