ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/Striped64.java
Revision: 1.7
Committed: Wed Jan 9 02:51:37 2013 UTC (11 years, 4 months ago) by jsr166
Branch: MAIN
Changes since 1.6: +17 -16 lines
Log Message:
more portable getUnsafe()

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 package jsr166e;
8 import java.util.Random;
9
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 must publicly do so.
14 */
15 abstract class Striped64 extends Number {
16 /*
17 * This class maintains a lazily-initialized table of atomically
18 * updated variables, plus an extra "base" field. The table size
19 * is a power of two. Indexing uses masked per-thread hash codes.
20 * Nearly all declarations in this class are package-private,
21 * accessed directly by subclasses.
22 *
23 * Table entries are of class Cell; a variant of AtomicLong padded
24 * to reduce cache contention on most processors. Padding is
25 * overkill for most Atomics because they are usually irregularly
26 * scattered in memory and thus don't interfere much with each
27 * other. But Atomic objects residing in arrays will tend to be
28 * placed adjacent to each other, and so will most often share
29 * cache lines (with a huge negative performance impact) without
30 * this precaution.
31 *
32 * In part because Cells are relatively large, we avoid creating
33 * them until they are needed. When there is no contention, all
34 * updates are made to the base field. Upon first contention (a
35 * failed CAS on base update), the table is initialized to size 2.
36 * The table size is doubled upon further contention until
37 * reaching the nearest power of two greater than or equal to the
38 * number of CPUS. Table slots remain empty (null) until they are
39 * needed.
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
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.
47 *
48 * Per-thread hash codes are initialized to random values.
49 * Contention and/or table collisions are indicated by failed
50 * CASes when performing an update operation (see method
51 * retryUpdate). Upon a collision, if the table size is less than
52 * the capacity, it is doubled in size unless some other thread
53 * holds the lock. If a hashed slot is empty, and lock is
54 * available, a new Cell is created. Otherwise, if the slot
55 * exists, a CAS is tried. Retries proceed by "double hashing",
56 * using a secondary hash (Marsaglia XorShift) to try to find a
57 * free slot.
58 *
59 * The table size is capped because, when there are more threads
60 * than CPUs, supposing that each thread were bound to a CPU,
61 * there would exist a perfect hash function mapping threads to
62 * slots that eliminates collisions. When we reach capacity, we
63 * search for this mapping by randomly varying the hash codes of
64 * colliding threads. Because search is random, and collisions
65 * only become known via CAS failures, convergence can be slow,
66 * and because threads are typically not bound to CPUS forever,
67 * may not occur at all. However, despite these limitations,
68 * observed contention rates are typically low in these cases.
69 *
70 * It is possible for a Cell to become unused when threads that
71 * once hashed to it terminate, as well as in the case where
72 * doubling the table causes no thread to hash to it under
73 * expanded mask. We do not try to detect or remove such cells,
74 * under the assumption that for long-running instances, observed
75 * contention levels will recur, so the cells will eventually be
76 * needed again; and for short-lived ones, it does not matter.
77 */
78
79 /**
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.
86 */
87 static final class Cell {
88 volatile long p0, p1, p2, p3, p4, p5, p6;
89 volatile long value;
90 volatile long q0, q1, q2, q3, q4, q5, q6;
91 Cell(long x) { value = x; }
92
93 final boolean cas(long cmp, long val) {
94 return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);
95 }
96
97 // Unsafe mechanics
98 private static final sun.misc.Unsafe UNSAFE;
99 private static final long valueOffset;
100 static {
101 try {
102 UNSAFE = getUnsafe();
103 Class<?> ak = Cell.class;
104 valueOffset = UNSAFE.objectFieldOffset
105 (ak.getDeclaredField("value"));
106 } catch (Exception e) {
107 throw new Error(e);
108 }
109 }
110
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.
116 */
117 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 }
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();
140
141 /** Number of CPUS, to place bound on table size */
142 static final int NCPU = Runtime.getRuntime().availableProcessors();
143
144 /**
145 * Table of cells. When non-null, size is a power of 2.
146 */
147 transient volatile Cell[] cells;
148
149 /**
150 * Base value, used mainly when there is no contention, but also as
151 * a fallback during table initialization races. Updated via CAS.
152 */
153 transient volatile long base;
154
155 /**
156 * Spinlock (locked via CAS) used when resizing and/or creating Cells.
157 */
158 transient volatile int busy;
159
160 /**
161 * Package-private default constructor
162 */
163 Striped64() {
164 }
165
166 /**
167 * CASes the base field.
168 */
169 final boolean casBase(long cmp, long val) {
170 return UNSAFE.compareAndSwapLong(this, baseOffset, cmp, val);
171 }
172
173 /**
174 * CASes the busy field from 0 to 1 to acquire lock.
175 */
176 final boolean casBusy() {
177 return UNSAFE.compareAndSwapInt(this, busyOffset, 0, 1);
178 }
179
180 /**
181 * Computes the function of current and new value. Subclasses
182 * should open-code this update function for most uses, but the
183 * virtualized form is needed within retryUpdate.
184 *
185 * @param currentValue the current value (of either base or a cell)
186 * @param newValue the argument from a user update call
187 * @return result of the update function
188 */
189 abstract long fn(long currentValue, long newValue);
190
191 /**
192 * Handles cases of updates involving initialization, resizing,
193 * creating new Cells, and/or contention. See above for
194 * explanation. This method suffers the usual non-modularity
195 * problems of optimistic retry code, relying on rechecked sets of
196 * reads.
197 *
198 * @param x the value
199 * @param hc the hash code holder
200 * @param wasUncontended false if CAS failed before call
201 */
202 final void retryUpdate(long x, HashCode hc, boolean wasUncontended) {
203 int h = hc.code;
204 boolean collide = false; // True if last slot nonempty
205 for (;;) {
206 Cell[] as; Cell a; int n; long v;
207 if ((as = cells) != null && (n = as.length) > 0) {
208 if ((a = as[(n - 1) & h]) == null) {
209 if (busy == 0) { // Try to attach new Cell
210 Cell r = new Cell(x); // Optimistically create
211 if (busy == 0 && casBusy()) {
212 boolean created = false;
213 try { // Recheck under lock
214 Cell[] rs; int m, j;
215 if ((rs = cells) != null &&
216 (m = rs.length) > 0 &&
217 rs[j = (m - 1) & h] == null) {
218 rs[j] = r;
219 created = true;
220 }
221 } finally {
222 busy = 0;
223 }
224 if (created)
225 break;
226 continue; // Slot is now non-empty
227 }
228 }
229 collide = false;
230 }
231 else if (!wasUncontended) // CAS already known to fail
232 wasUncontended = true; // Continue after rehash
233 else if (a.cas(v = a.value, fn(v, x)))
234 break;
235 else if (n >= NCPU || cells != as)
236 collide = false; // At max size or stale
237 else if (!collide)
238 collide = true;
239 else if (busy == 0 && casBusy()) {
240 try {
241 if (cells == as) { // Expand table unless stale
242 Cell[] rs = new Cell[n << 1];
243 for (int i = 0; i < n; ++i)
244 rs[i] = as[i];
245 cells = rs;
246 }
247 } finally {
248 busy = 0;
249 }
250 collide = false;
251 continue; // Retry with expanded table
252 }
253 h ^= h << 13; // Rehash
254 h ^= h >>> 17;
255 h ^= h << 5;
256 }
257 else if (busy == 0 && cells == as && casBusy()) {
258 boolean init = false;
259 try { // Initialize table
260 if (cells == as) {
261 Cell[] rs = new Cell[2];
262 rs[h & 1] = new Cell(x);
263 cells = rs;
264 init = true;
265 }
266 } finally {
267 busy = 0;
268 }
269 if (init)
270 break;
271 }
272 else if (casBase(v = base, fn(v, x)))
273 break; // Fall back on using base
274 }
275 hc.code = h; // Record index for next time
276 }
277
278
279 /**
280 * Sets base and all cells to the given value.
281 */
282 final void internalReset(long initialValue) {
283 Cell[] as = cells;
284 base = initialValue;
285 if (as != null) {
286 int n = as.length;
287 for (int i = 0; i < n; ++i) {
288 Cell a = as[i];
289 if (a != null)
290 a.value = initialValue;
291 }
292 }
293 }
294
295 // Unsafe mechanics
296 private static final sun.misc.Unsafe UNSAFE;
297 private static final long baseOffset;
298 private static final long busyOffset;
299 static {
300 try {
301 UNSAFE = getUnsafe();
302 Class<?> sk = Striped64.class;
303 baseOffset = UNSAFE.objectFieldOffset
304 (sk.getDeclaredField("base"));
305 busyOffset = UNSAFE.objectFieldOffset
306 (sk.getDeclaredField("busy"));
307 } catch (Exception e) {
308 throw new Error(e);
309 }
310 }
311
312 /**
313 * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
314 * Replace with a simple call to Unsafe.getUnsafe when integrating
315 * into a jdk.
316 *
317 * @return a sun.misc.Unsafe
318 */
319 private static sun.misc.Unsafe getUnsafe() {
320 try {
321 return sun.misc.Unsafe.getUnsafe();
322 } catch (SecurityException tryReflectionInstead) {}
323 try {
324 return java.security.AccessController.doPrivileged
325 (new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
326 public sun.misc.Unsafe run() throws Exception {
327 Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
328 for (java.lang.reflect.Field f : k.getDeclaredFields()) {
329 f.setAccessible(true);
330 Object x = f.get(null);
331 if (k.isInstance(x))
332 return k.cast(x);
333 }
334 throw new NoSuchFieldError("the Unsafe");
335 }});
336 } catch (java.security.PrivilegedActionException e) {
337 throw new RuntimeException("Could not initialize intrinsics",
338 e.getCause());
339 }
340 }
341 }