ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/StampedLock.java
Revision: 1.35
Committed: Mon Jan 28 22:22:08 2013 UTC (11 years, 3 months ago) by jsr166
Branch: MAIN
Changes since 1.34: +5 -3 lines
Log Message:
fix "ant lint" javadoc warnings

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
9 import java.util.concurrent.ThreadLocalRandom;
10 import java.util.concurrent.TimeUnit;
11 import java.util.concurrent.locks.Lock;
12 import java.util.concurrent.locks.Condition;
13 import java.util.concurrent.locks.ReadWriteLock;
14 import java.util.concurrent.locks.LockSupport;
15
16 /**
17 * A capability-based lock with three modes for controlling read/write
18 * access. The state of a StampedLock consists of a version and mode.
19 * Lock acquisition methods return a stamp that represents and
20 * controls access with respect to a lock state; "try" versions of
21 * these methods may instead return the special value zero to
22 * represent failure to acquire access. Lock release and conversion
23 * methods require stamps as arguments, and fail if they do not match
24 * the state of the lock. The three modes are:
25 *
26 * <ul>
27 *
28 * <li><b>Writing.</b> Method {@link #writeLock} possibly blocks
29 * waiting for exclusive access, returning a stamp that can be used
30 * in method {@link #unlockWrite} to release the lock. Untimed and
31 * timed versions of {@code tryWriteLock} are also provided. When
32 * the lock is held in write mode, no read locks may be obtained,
33 * and all optimistic read validations will fail. </li>
34 *
35 * <li><b>Reading.</b> Method {@link #readLock} possibly blocks
36 * waiting for non-exclusive access, returning a stamp that can be
37 * used in method {@link #unlockRead} to release the lock. Untimed
38 * and timed versions of {@code tryReadLock} are also provided. </li>
39 *
40 * <li><b>Optimistic Reading.</b> Method {@link #tryOptimisticRead}
41 * returns a non-zero stamp only if the lock is not currently held
42 * in write mode. Method {@link #validate} returns true if the lock
43 * has not been acquired in write mode since obtaining a given
44 * stamp. This mode can be thought of as an extremely weak version
45 * of a read-lock, that can be broken by a writer at any time. The
46 * use of optimistic mode for short read-only code segments often
47 * reduces contention and improves throughput. However, its use is
48 * inherently fragile. Optimistic read sections should only read
49 * fields and hold them in local variables for later use after
50 * validation. Fields read while in optimistic mode may be wildly
51 * inconsistent, so usage applies only when you are familiar enough
52 * with data representations to check consistency and/or repeatedly
53 * invoke method {@code validate()}. For example, such steps are
54 * typically required when first reading an object or array
55 * reference, and then accessing one of its fields, elements or
56 * methods. </li>
57 *
58 * </ul>
59 *
60 * <p>This class also supports methods that conditionally provide
61 * conversions across the three modes. For example, method {@link
62 * #tryConvertToWriteLock} attempts to "upgrade" a mode, returning
63 * a valid write stamp if (1) already in writing mode (2) in reading
64 * mode and there are no other readers or (3) in optimistic mode and
65 * the lock is available. The forms of these methods are designed to
66 * help reduce some of the code bloat that otherwise occurs in
67 * retry-based designs.
68 *
69 * <p>StampedLocks are designed for use as internal utilities in the
70 * development of thread-safe components. Their use relies on
71 * knowledge of the internal properties of the data, objects, and
72 * methods they are protecting. They are not reentrant, so locked
73 * bodies should not call other unknown methods that may try to
74 * re-acquire locks (although you may pass a stamp to other methods
75 * that can use or convert it). The use of read lock modes relies on
76 * the associated code sections being side-effect-free. Unvalidated
77 * optimistic read sections cannot call methods that are not known to
78 * tolerate potential inconsistencies. Stamps use finite
79 * representations, and are not cryptographically secure (i.e., a
80 * valid stamp may be guessable). Stamp values may recycle after (no
81 * sooner than) one year of continuous operation. A stamp held without
82 * use or validation for longer than this period may fail to validate
83 * correctly. StampedLocks are serializable, but always deserialize
84 * into initial unlocked state, so they are not useful for remote
85 * locking.
86 *
87 * <p>The scheduling policy of StampedLock does not consistently
88 * prefer readers over writers or vice versa. All "try" methods are
89 * best-effort and do not necessarily conform to any scheduling or
90 * fairness policy. A zero return from any "try" method for acquiring
91 * or converting locks does not carry any information about the state
92 * of the lock; a subsequent invocation may succeed.
93 *
94 * <p>Because it supports coordinated usage across multiple lock
95 * modes, this class does not directly implement the {@link Lock} or
96 * {@link ReadWriteLock} interfaces. However, a StampedLock may be
97 * viewed {@link #asReadLock()}, {@link #asWriteLock()}, or {@link
98 * #asReadWriteLock()} in applications requiring only the associated
99 * set of functionality.
100 *
101 * <p><b>Sample Usage.</b> The following illustrates some usage idioms
102 * in a class that maintains simple two-dimensional points. The sample
103 * code illustrates some try/catch conventions even though they are
104 * not strictly needed here because no exceptions can occur in their
105 * bodies.<br>
106 *
107 * <pre>{@code
108 * class Point {
109 * private double x, y;
110 * private final StampedLock sl = new StampedLock();
111 *
112 * void move(double deltaX, double deltaY) { // an exclusively locked method
113 * long stamp = sl.writeLock();
114 * try {
115 * x += deltaX;
116 * y += deltaY;
117 * } finally {
118 * sl.unlockWrite(stamp);
119 * }
120 * }
121 *
122 * double distanceFromOriginV1() { // A read-only method
123 * long stamp;
124 * if ((stamp = sl.tryOptimisticRead()) != 0L) { // optimistic
125 * double currentX = x;
126 * double currentY = y;
127 * if (sl.validate(stamp))
128 * return Math.sqrt(currentX * currentX + currentY * currentY);
129 * }
130 * stamp = sl.readLock(); // fall back to read lock
131 * try {
132 * double currentX = x;
133 * double currentY = y;
134 * return Math.sqrt(currentX * currentX + currentY * currentY);
135 * } finally {
136 * sl.unlockRead(stamp);
137 * }
138 * }
139 *
140 * double distanceFromOriginV2() { // combines code paths
141 * double currentX = 0.0, currentY = 0.0;
142 * for (long stamp = sl.tryOptimisticRead(); ; stamp = sl.readLock()) {
143 * try {
144 * currentX = x;
145 * currentY = y;
146 * } finally {
147 * if (sl.tryConvertToOptimisticRead(stamp) != 0L) // unlock or validate
148 * break;
149 * }
150 * }
151 * return Math.sqrt(currentX * currentX + currentY * currentY);
152 * }
153 *
154 * void moveIfAtOrigin(double newX, double newY) { // upgrade
155 * // Could instead start with optimistic, not read mode
156 * long stamp = sl.readLock();
157 * try {
158 * while (x == 0.0 && y == 0.0) {
159 * long ws = sl.tryConvertToWriteLock(stamp);
160 * if (ws != 0L) {
161 * stamp = ws;
162 * x = newX;
163 * y = newY;
164 * break;
165 * }
166 * else {
167 * sl.unlockRead(stamp);
168 * stamp = sl.writeLock();
169 * }
170 * }
171 * } finally {
172 * sl.unlock(stamp);
173 * }
174 * }
175 * }}</pre>
176 *
177 * @since 1.8
178 * @author Doug Lea
179 */
180 public class StampedLock implements java.io.Serializable {
181 /*
182 * Algorithmic notes:
183 *
184 * The design employs elements of Sequence locks
185 * (as used in linux kernels; see Lameter's
186 * http://www.lameter.com/gelato2005.pdf
187 * and elsewhere; see
188 * Boehm's http://www.hpl.hp.com/techreports/2012/HPL-2012-68.html)
189 * and Ordered RW locks (see Shirako et al
190 * http://dl.acm.org/citation.cfm?id=2312015)
191 *
192 * Conceptually, the primary state of the lock includes a sequence
193 * number that is odd when write-locked and even otherwise.
194 * However, this is offset by a reader count that is non-zero when
195 * read-locked. The read count is ignored when validating
196 * "optimistic" seqlock-reader-style stamps. Because we must use
197 * a small finite number of bits (currently 7) for readers, a
198 * supplementary reader overflow word is used when the number of
199 * readers exceeds the count field. We do this by treating the max
200 * reader count value (RBITS) as a spinlock protecting overflow
201 * updates.
202 *
203 * Waiters use a modified form of CLH lock used in
204 * AbstractQueuedSynchronizer (see its internal documentation for
205 * a fuller account), where each node is tagged (field mode) as
206 * either a reader or writer. Sets of waiting readers are grouped
207 * (linked) under a common node (field cowait) so act as a single
208 * node with respect to most CLH mechanics. By virtue of the
209 * queue structure, wait nodes need not actually carry sequence
210 * numbers; we know each is greater than its predecessor. This
211 * simplifies the scheduling policy to a mainly-FIFO scheme that
212 * incorporates elements of Phase-Fair locks (see Brandenburg &
213 * Anderson, especially http://www.cs.unc.edu/~bbb/diss/). In
214 * particular, we use the phase-fair anti-barging rule: If an
215 * incoming reader arrives while read lock is held but there is a
216 * queued writer, this incoming reader is queued. (This rule is
217 * responsible for some of the complexity of method acquireRead,
218 * but without it, the lock becomes highly unfair.)
219 *
220 * These rules apply to threads actually queued. All tryLock forms
221 * opportunistically try to acquire locks regardless of preference
222 * rules, and so may "barge" their way in. Randomized spinning is
223 * used in the acquire methods to reduce (increasingly expensive)
224 * context switching while also avoiding sustained memory
225 * thrashing among many threads. We limit spins to the head of
226 * queue. A thread spin-waits up to SPINS times (where each
227 * iteration decreases spin count with 50% probability) before
228 * blocking. If, upon wakening it fails to obtain lock, and is
229 * still (or becomes) the first waiting thread (which indicates
230 * that some other thread barged and obtained lock), it escalates
231 * spins (up to MAX_HEAD_SPINS) to reduce the likelihood of
232 * continually losing to barging threads.
233 *
234 * Nearly all of these mechanics are carried out in methods
235 * acquireWrite and acquireRead, that, as typical of such code,
236 * sprawl out because actions and retries rely on consistent sets
237 * of locally cached reads.
238 *
239 * As noted in Boehm's paper (above), sequence validation (mainly
240 * method validate()) requires stricter ordering rules than apply
241 * to normal volatile reads (of "state"). In the absence of (but
242 * continual hope for) explicit JVM support of intrinsics with
243 * double-sided reordering prohibition, or corresponding fence
244 * intrinsics, we for now uncomfortably rely on the fact that the
245 * Unsafe.getXVolatile intrinsic must have this property
246 * (syntactic volatile reads do not) for internal purposes anyway,
247 * even though it is not documented.
248 *
249 * The memory layout keeps lock state and queue pointers together
250 * (normally on the same cache line). This usually works well for
251 * read-mostly loads. In most other cases, the natural tendency of
252 * adaptive-spin CLH locks to reduce memory contention lessens
253 * motivation to further spread out contended locations, but might
254 * be subject to future improvements.
255 */
256
257 private static final long serialVersionUID = -6001602636862214147L;
258
259 /** Number of processors, for spin control */
260 private static final int NCPU = Runtime.getRuntime().availableProcessors();
261
262 /** Maximum number of retries before blocking on acquisition */
263 private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;
264
265 /** Maximum number of retries before re-blocking */
266 private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 12 : 0;
267
268 /** The period for yielding when waiting for overflow spinlock */
269 private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
270
271 /** The number of bits to use for reader count before overflowing */
272 private static final int LG_READERS = 7;
273
274 // Values for lock state and stamp operations
275 private static final long RUNIT = 1L;
276 private static final long WBIT = 1L << LG_READERS;
277 private static final long RBITS = WBIT - 1L;
278 private static final long RFULL = RBITS - 1L;
279 private static final long ABITS = RBITS | WBIT;
280 private static final long SBITS = ~RBITS; // note overlap with ABITS
281
282 // Initial value for lock state; avoid failure value zero
283 private static final long ORIGIN = WBIT << 1;
284
285 // Special value from cancelled acquire methods so caller can throw IE
286 private static final long INTERRUPTED = 1L;
287
288 // Values for node status; order matters
289 private static final int WAITING = -1;
290 private static final int CANCELLED = 1;
291
292 // Modes for nodes (int not boolean to allow arithmetic)
293 private static final int RMODE = 0;
294 private static final int WMODE = 1;
295
296 /** Wait nodes */
297 static final class WNode {
298 volatile WNode prev;
299 volatile WNode next;
300 volatile WNode cowait; // list of linked readers
301 volatile Thread thread; // non-null while possibly parked
302 volatile int status; // 0, WAITING, or CANCELLED
303 final int mode; // RMODE or WMODE
304 WNode(int m, WNode p) { mode = m; prev = p; }
305 }
306
307 /** Head of CLH queue */
308 private transient volatile WNode whead;
309 /** Tail (last) of CLH queue */
310 private transient volatile WNode wtail;
311
312 // views
313 transient ReadLockView readLockView;
314 transient WriteLockView writeLockView;
315 transient ReadWriteLockView readWriteLockView;
316
317 /** Lock sequence/state */
318 private transient volatile long state;
319 /** extra reader count when state read count saturated */
320 private transient int readerOverflow;
321
322 /**
323 * Creates a new lock, initially in unlocked state.
324 */
325 public StampedLock() {
326 state = ORIGIN;
327 }
328
329 /**
330 * Exclusively acquires the lock, blocking if necessary
331 * until available.
332 *
333 * @return a stamp that can be used to unlock or convert mode
334 */
335 public long writeLock() {
336 long s, next; // bypass acquireWrite in fully unlocked case only
337 return ((((s = state) & ABITS) == 0L &&
338 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
339 next : acquireWrite(false, 0L));
340 }
341
342 /**
343 * Exclusively acquires the lock if it is immediately available.
344 *
345 * @return a stamp that can be used to unlock or convert mode,
346 * or zero if the lock is not available
347 */
348 public long tryWriteLock() {
349 long s, next;
350 return ((((s = state) & ABITS) == 0L &&
351 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
352 next : 0L);
353 }
354
355 /**
356 * Exclusively acquires the lock if it is available within the
357 * given time and the current thread has not been interrupted.
358 * Behavior under timeout and interruption matches that specified
359 * for method {@link Lock#tryLock(long,TimeUnit)}.
360 *
361 * @return a stamp that can be used to unlock or convert mode,
362 * or zero if the lock is not available
363 * @throws InterruptedException if the current thread is interrupted
364 * before acquiring the lock
365 */
366 public long tryWriteLock(long time, TimeUnit unit)
367 throws InterruptedException {
368 long nanos = unit.toNanos(time);
369 if (!Thread.interrupted()) {
370 long next, deadline;
371 if ((next = tryWriteLock()) != 0L)
372 return next;
373 if (nanos <= 0L)
374 return 0L;
375 if ((deadline = System.nanoTime() + nanos) == 0L)
376 deadline = 1L;
377 if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
378 return next;
379 }
380 throw new InterruptedException();
381 }
382
383 /**
384 * Exclusively acquires the lock, blocking if necessary
385 * until available or the current thread is interrupted.
386 * Behavior under interruption matches that specified
387 * for method {@link Lock#lockInterruptibly()}.
388 *
389 * @return a stamp that can be used to unlock or convert mode
390 * @throws InterruptedException if the current thread is interrupted
391 * before acquiring the lock
392 */
393 public long writeLockInterruptibly() throws InterruptedException {
394 long next;
395 if (!Thread.interrupted() &&
396 (next = acquireWrite(true, 0L)) != INTERRUPTED)
397 return next;
398 throw new InterruptedException();
399 }
400
401 /**
402 * Non-exclusively acquires the lock, blocking if necessary
403 * until available.
404 *
405 * @return a stamp that can be used to unlock or convert mode
406 */
407 public long readLock() {
408 long s, next; // bypass acquireRead on fully unlocked case only
409 return ((((s = state) & ABITS) == 0L &&
410 U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
411 next : acquireRead(false, 0L));
412 }
413
414 /**
415 * Non-exclusively acquires the lock if it is immediately available.
416 *
417 * @return a stamp that can be used to unlock or convert mode,
418 * or zero if the lock is not available
419 */
420 public long tryReadLock() {
421 for (;;) {
422 long s, m, next;
423 if ((m = (s = state) & ABITS) == WBIT)
424 return 0L;
425 else if (m < RFULL) {
426 if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
427 return next;
428 }
429 else if ((next = tryIncReaderOverflow(s)) != 0L)
430 return next;
431 }
432 }
433
434 /**
435 * Non-exclusively acquires the lock if it is available within the
436 * given time and the current thread has not been interrupted.
437 * Behavior under timeout and interruption matches that specified
438 * for method {@link Lock#tryLock(long,TimeUnit)}.
439 *
440 * @return a stamp that can be used to unlock or convert mode,
441 * or zero if the lock is not available
442 * @throws InterruptedException if the current thread is interrupted
443 * before acquiring the lock
444 */
445 public long tryReadLock(long time, TimeUnit unit)
446 throws InterruptedException {
447 long s, m, next, deadline;
448 long nanos = unit.toNanos(time);
449 if (!Thread.interrupted()) {
450 if ((m = (s = state) & ABITS) != WBIT) {
451 if (m < RFULL) {
452 if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
453 return next;
454 }
455 else if ((next = tryIncReaderOverflow(s)) != 0L)
456 return next;
457 }
458 if (nanos <= 0L)
459 return 0L;
460 if ((deadline = System.nanoTime() + nanos) == 0L)
461 deadline = 1L;
462 if ((next = acquireRead(true, deadline)) != INTERRUPTED)
463 return next;
464 }
465 throw new InterruptedException();
466 }
467
468 /**
469 * Non-exclusively acquires the lock, blocking if necessary
470 * until available or the current thread is interrupted.
471 * Behavior under interruption matches that specified
472 * for method {@link Lock#lockInterruptibly()}.
473 *
474 * @return a stamp that can be used to unlock or convert mode
475 * @throws InterruptedException if the current thread is interrupted
476 * before acquiring the lock
477 */
478 public long readLockInterruptibly() throws InterruptedException {
479 long next;
480 if (!Thread.interrupted() &&
481 (next = acquireRead(true, 0L)) != INTERRUPTED)
482 return next;
483 throw new InterruptedException();
484 }
485
486 /**
487 * Returns a stamp that can later be validated, or zero
488 * if exclusively locked.
489 *
490 * @return a stamp, or zero if exclusively locked
491 */
492 public long tryOptimisticRead() {
493 long s;
494 return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
495 }
496
497 /**
498 * Returns true if the lock has not been exclusively acquired
499 * since issuance of the given stamp. Always returns false if the
500 * stamp is zero. Always returns true if the stamp represents a
501 * currently held lock. Invoking this method with a value not
502 * obtained from {@link #tryOptimisticRead} or a locking method
503 * for this lock has no defined effect or result.
504 *
505 * @return true if the lock has not been exclusively acquired
506 * since issuance of the given stamp; else false
507 */
508 public boolean validate(long stamp) {
509 // See above about current use of getLongVolatile here
510 return (stamp & SBITS) == (U.getLongVolatile(this, STATE) & SBITS);
511 }
512
513 /**
514 * If the lock state matches the given stamp, releases the
515 * exclusive lock.
516 *
517 * @param stamp a stamp returned by a write-lock operation
518 * @throws IllegalMonitorStateException if the stamp does
519 * not match the current state of this lock
520 */
521 public void unlockWrite(long stamp) {
522 WNode h;
523 if (state != stamp || (stamp & WBIT) == 0L)
524 throw new IllegalMonitorStateException();
525 state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
526 if ((h = whead) != null && h.status != 0)
527 release(h);
528 }
529
530 /**
531 * If the lock state matches the given stamp, releases the
532 * non-exclusive lock.
533 *
534 * @param stamp a stamp returned by a read-lock operation
535 * @throws IllegalMonitorStateException if the stamp does
536 * not match the current state of this lock
537 */
538 public void unlockRead(long stamp) {
539 long s, m; WNode h;
540 for (;;) {
541 if (((s = state) & SBITS) != (stamp & SBITS) ||
542 (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
543 throw new IllegalMonitorStateException();
544 if (m < RFULL) {
545 if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
546 if (m == RUNIT && (h = whead) != null && h.status != 0)
547 release(h);
548 break;
549 }
550 }
551 else if (tryDecReaderOverflow(s) != 0L)
552 break;
553 }
554 }
555
556 /**
557 * If the lock state matches the given stamp, releases the
558 * corresponding mode of the lock.
559 *
560 * @param stamp a stamp returned by a lock operation
561 * @throws IllegalMonitorStateException if the stamp does
562 * not match the current state of this lock
563 */
564 public void unlock(long stamp) {
565 long a = stamp & ABITS, m, s; WNode h;
566 while (((s = state) & SBITS) == (stamp & SBITS)) {
567 if ((m = s & ABITS) == 0L)
568 break;
569 else if (m == WBIT) {
570 if (a != m)
571 break;
572 state = (s += WBIT) == 0L ? ORIGIN : s;
573 if ((h = whead) != null && h.status != 0)
574 release(h);
575 return;
576 }
577 else if (a == 0L || a >= WBIT)
578 break;
579 else if (m < RFULL) {
580 if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
581 if (m == RUNIT && (h = whead) != null && h.status != 0)
582 release(h);
583 return;
584 }
585 }
586 else if (tryDecReaderOverflow(s) != 0L)
587 return;
588 }
589 throw new IllegalMonitorStateException();
590 }
591
592 /**
593 * If the lock state matches the given stamp, performs one of
594 * the following actions. If the stamp represents holding a write
595 * lock, returns it. Or, if a read lock, if the write lock is
596 * available, releases the read lock and returns a write stamp.
597 * Or, if an optimistic read, returns a write stamp only if
598 * immediately available. This method returns zero in all other
599 * cases.
600 *
601 * @param stamp a stamp
602 * @return a valid write stamp, or zero on failure
603 */
604 public long tryConvertToWriteLock(long stamp) {
605 long a = stamp & ABITS, m, s, next;
606 while (((s = state) & SBITS) == (stamp & SBITS)) {
607 if ((m = s & ABITS) == 0L) {
608 if (a != 0L)
609 break;
610 if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
611 return next;
612 }
613 else if (m == WBIT) {
614 if (a != m)
615 break;
616 return stamp;
617 }
618 else if (m == RUNIT && a != 0L) {
619 if (U.compareAndSwapLong(this, STATE, s,
620 next = s - RUNIT + WBIT))
621 return next;
622 }
623 else
624 break;
625 }
626 return 0L;
627 }
628
629 /**
630 * If the lock state matches the given stamp, performs one of
631 * the following actions. If the stamp represents holding a write
632 * lock, releases it and obtains a read lock. Or, if a read lock,
633 * returns it. Or, if an optimistic read, acquires a read lock and
634 * returns a read stamp only if immediately available. This method
635 * returns zero in all other cases.
636 *
637 * @param stamp a stamp
638 * @return a valid read stamp, or zero on failure
639 */
640 public long tryConvertToReadLock(long stamp) {
641 long a = stamp & ABITS, m, s, next; WNode h;
642 while (((s = state) & SBITS) == (stamp & SBITS)) {
643 if ((m = s & ABITS) == 0L) {
644 if (a != 0L)
645 break;
646 else if (m < RFULL) {
647 if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
648 return next;
649 }
650 else if ((next = tryIncReaderOverflow(s)) != 0L)
651 return next;
652 }
653 else if (m == WBIT) {
654 if (a != m)
655 break;
656 state = next = s + (WBIT + RUNIT);
657 if ((h = whead) != null && h.status != 0)
658 release(h);
659 return next;
660 }
661 else if (a != 0L && a < WBIT)
662 return stamp;
663 else
664 break;
665 }
666 return 0L;
667 }
668
669 /**
670 * If the lock state matches the given stamp then, if the stamp
671 * represents holding a lock, releases it and returns an
672 * observation stamp. Or, if an optimistic read, returns it if
673 * validated. This method returns zero in all other cases, and so
674 * may be useful as a form of "tryUnlock".
675 *
676 * @param stamp a stamp
677 * @return a valid optimistic read stamp, or zero on failure
678 */
679 public long tryConvertToOptimisticRead(long stamp) {
680 long a = stamp & ABITS, m, s, next; WNode h;
681 for (;;) {
682 s = U.getLongVolatile(this, STATE); // see above
683 if ((s & SBITS) != (stamp & SBITS))
684 break;
685 if ((m = s & ABITS) == 0L) {
686 if (a != 0L)
687 break;
688 return s;
689 }
690 else if (m == WBIT) {
691 if (a != m)
692 break;
693 state = next = (s += WBIT) == 0L ? ORIGIN : s;
694 if ((h = whead) != null && h.status != 0)
695 release(h);
696 return next;
697 }
698 else if (a == 0L || a >= WBIT)
699 break;
700 else if (m < RFULL) {
701 if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
702 if (m == RUNIT && (h = whead) != null && h.status != 0)
703 release(h);
704 return next & SBITS;
705 }
706 }
707 else if ((next = tryDecReaderOverflow(s)) != 0L)
708 return next & SBITS;
709 }
710 return 0L;
711 }
712
713 /**
714 * Releases the write lock if it is held, without requiring a
715 * stamp value. This method may be useful for recovery after
716 * errors.
717 *
718 * @return true if the lock was held, else false
719 */
720 public boolean tryUnlockWrite() {
721 long s; WNode h;
722 if (((s = state) & WBIT) != 0L) {
723 state = (s += WBIT) == 0L ? ORIGIN : s;
724 if ((h = whead) != null && h.status != 0)
725 release(h);
726 return true;
727 }
728 return false;
729 }
730
731 /**
732 * Releases one hold of the read lock if it is held, without
733 * requiring a stamp value. This method may be useful for recovery
734 * after errors.
735 *
736 * @return true if the read lock was held, else false
737 */
738 public boolean tryUnlockRead() {
739 long s, m; WNode h;
740 while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
741 if (m < RFULL) {
742 if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
743 if (m == RUNIT && (h = whead) != null && h.status != 0)
744 release(h);
745 return true;
746 }
747 }
748 else if (tryDecReaderOverflow(s) != 0L)
749 return true;
750 }
751 return false;
752 }
753
754 /**
755 * Returns true if the lock is currently held exclusively.
756 *
757 * @return true if the lock is currently held exclusively
758 */
759 public boolean isWriteLocked() {
760 return (state & WBIT) != 0L;
761 }
762
763 /**
764 * Returns true if the lock is currently held non-exclusively.
765 *
766 * @return true if the lock is currently held non-exclusively
767 */
768 public boolean isReadLocked() {
769 return (state & RBITS) != 0L;
770 }
771
772 private void readObject(java.io.ObjectInputStream s)
773 throws java.io.IOException, ClassNotFoundException {
774 s.defaultReadObject();
775 state = ORIGIN; // reset to unlocked state
776 }
777
778 /**
779 * Returns a plain {@link Lock} view of this StampedLock in which
780 * the {@link Lock#lock} method is mapped to {@link #readLock},
781 * and similarly for other methods. The returned Lock does not
782 * support a {@link Condition}; method {@link
783 * Lock#newCondition()} throws {@code
784 * UnsupportedOperationException}.
785 *
786 * @return the lock
787 */
788 public Lock asReadLock() {
789 ReadLockView v;
790 return ((v = readLockView) != null ? v :
791 (readLockView = new ReadLockView()));
792 }
793
794 /**
795 * Returns a plain {@link Lock} view of this StampedLock in which
796 * the {@link Lock#lock} method is mapped to {@link #writeLock},
797 * and similarly for other methods. The returned Lock does not
798 * support a {@link Condition}; method {@link
799 * Lock#newCondition()} throws {@code
800 * UnsupportedOperationException}.
801 *
802 * @return the lock
803 */
804 public Lock asWriteLock() {
805 WriteLockView v;
806 return ((v = writeLockView) != null ? v :
807 (writeLockView = new WriteLockView()));
808 }
809
810 /**
811 * Returns a {@link ReadWriteLock} view of this StampedLock in
812 * which the {@link ReadWriteLock#readLock()} method is mapped to
813 * {@link #asReadLock()}, and {@link ReadWriteLock#writeLock()} to
814 * {@link #asWriteLock()}.
815 *
816 * @return the lock
817 */
818 public ReadWriteLock asReadWriteLock() {
819 ReadWriteLockView v;
820 return ((v = readWriteLockView) != null ? v :
821 (readWriteLockView = new ReadWriteLockView()));
822 }
823
824 // view classes
825
826 final class ReadLockView implements Lock {
827 public void lock() { readLock(); }
828 public void lockInterruptibly() throws InterruptedException {
829 readLockInterruptibly();
830 }
831 public boolean tryLock() { return tryReadLock() != 0L; }
832 public boolean tryLock(long time, TimeUnit unit)
833 throws InterruptedException {
834 return tryReadLock(time, unit) != 0L;
835 }
836 public void unlock() { unstampedUnlockRead(); }
837 public Condition newCondition() {
838 throw new UnsupportedOperationException();
839 }
840 }
841
842 final class WriteLockView implements Lock {
843 public void lock() { writeLock(); }
844 public void lockInterruptibly() throws InterruptedException {
845 writeLockInterruptibly();
846 }
847 public boolean tryLock() { return tryWriteLock() != 0L; }
848 public boolean tryLock(long time, TimeUnit unit)
849 throws InterruptedException {
850 return tryWriteLock(time, unit) != 0L;
851 }
852 public void unlock() { unstampedUnlockWrite(); }
853 public Condition newCondition() {
854 throw new UnsupportedOperationException();
855 }
856 }
857
858 final class ReadWriteLockView implements ReadWriteLock {
859 public Lock readLock() { return asReadLock(); }
860 public Lock writeLock() { return asWriteLock(); }
861 }
862
863 // Unlock methods without stamp argument checks for view classes.
864 // Needed because view-class lock methods throw away stamps.
865
866 final void unstampedUnlockWrite() {
867 WNode h; long s;
868 if (((s = state) & WBIT) == 0L)
869 throw new IllegalMonitorStateException();
870 state = (s += WBIT) == 0L ? ORIGIN : s;
871 if ((h = whead) != null && h.status != 0)
872 release(h);
873 }
874
875 final void unstampedUnlockRead() {
876 for (;;) {
877 long s, m; WNode h;
878 if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
879 throw new IllegalMonitorStateException();
880 else if (m < RFULL) {
881 if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
882 if (m == RUNIT && (h = whead) != null && h.status != 0)
883 release(h);
884 break;
885 }
886 }
887 else if (tryDecReaderOverflow(s) != 0L)
888 break;
889 }
890 }
891
892 // internals
893
894 /**
895 * Tries to increment readerOverflow by first setting state
896 * access bits value to RBITS, indicating hold of spinlock,
897 * then updating, then releasing.
898 *
899 * @param s a reader overflow stamp: (s & ABITS) >= RFULL
900 * @return new stamp on success, else zero
901 */
902 private long tryIncReaderOverflow(long s) {
903 // assert (s & ABITS) >= RFULL
904 if ((s & ABITS) == RFULL) {
905 if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
906 ++readerOverflow;
907 state = s;
908 return s;
909 }
910 }
911 else if ((ThreadLocalRandom.current().nextInt() &
912 OVERFLOW_YIELD_RATE) == 0)
913 Thread.yield();
914 return 0L;
915 }
916
917 /**
918 * Tries to decrement readerOverflow.
919 *
920 * @param s a reader overflow stamp: (s & ABITS) >= RFULL
921 * @return new stamp on success, else zero
922 */
923 private long tryDecReaderOverflow(long s) {
924 // assert (s & ABITS) >= RFULL
925 if ((s & ABITS) == RFULL) {
926 if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
927 int r; long next;
928 if ((r = readerOverflow) > 0) {
929 readerOverflow = r - 1;
930 next = s;
931 }
932 else
933 next = s - RUNIT;
934 state = next;
935 return next;
936 }
937 }
938 else if ((ThreadLocalRandom.current().nextInt() &
939 OVERFLOW_YIELD_RATE) == 0)
940 Thread.yield();
941 return 0L;
942 }
943
944 /**
945 * Wakes up the successor of h (normally whead). This is normally
946 * just h.next, but may require traversal from wtail if next
947 * pointers are lagging. This may fail to wake up an acquiring
948 * thread when one or more have been cancelled, but the cancel
949 * methods themselves provide extra safeguards to ensure liveness.
950 */
951 private void release(WNode h) {
952 if (h != null) {
953 WNode q; Thread w;
954 U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
955 if ((q = h.next) == null || q.status == CANCELLED) {
956 for (WNode t = wtail; t != null && t != h; t = t.prev)
957 if (t.status <= 0)
958 q = t;
959 }
960 if (q != null) {
961 for (WNode r = q;;) { // release co-waiters too
962 if ((w = r.thread) != null) {
963 r.thread = null;
964 U.unpark(w);
965 }
966 if ((r = q.cowait) == null)
967 break;
968 U.compareAndSwapObject(q, WCOWAIT, r, r.cowait);
969 }
970 }
971 }
972 }
973
974 /**
975 * See above for explanation.
976 *
977 * @param interruptible true if should check interrupts and if so
978 * return INTERRUPTED
979 * @param deadline if nonzero, the System.nanoTime value to timeout
980 * at (and return zero)
981 * @return next state, or INTERRUPTED
982 */
983 private long acquireWrite(boolean interruptible, long deadline) {
984 WNode node = null, p;
985 for (int spins = -1;;) { // spin while enqueuing
986 long s, ns;
987 if (((s = state) & ABITS) == 0L) {
988 if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
989 return ns;
990 }
991 else if (spins > 0) {
992 if (ThreadLocalRandom.current().nextInt() >= 0)
993 --spins;
994 }
995 else if ((p = wtail) == null) { // initialize queue
996 WNode h = new WNode(WMODE, null);
997 if (U.compareAndSwapObject(this, WHEAD, null, h))
998 wtail = h;
999 }
1000 else if (spins < 0)
1001 spins = (p == whead) ? SPINS : 0;
1002 else if (node == null)
1003 node = new WNode(WMODE, p);
1004 else if (node.prev != p)
1005 node.prev = p;
1006 else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
1007 p.next = node;
1008 break;
1009 }
1010 }
1011
1012 for (int spins = SPINS;;) {
1013 WNode np, pp; int ps; long s, ns; Thread w;
1014 while ((np = node.prev) != p && np != null)
1015 (p = np).next = node; // stale
1016 if (whead == p) {
1017 for (int k = spins;;) { // spin at head
1018 if (((s = state) & ABITS) == 0L) {
1019 if (U.compareAndSwapLong(this, STATE, s, ns = s+WBIT)) {
1020 whead = node;
1021 node.prev = null;
1022 return ns;
1023 }
1024 }
1025 else if (ThreadLocalRandom.current().nextInt() >= 0 &&
1026 --k <= 0)
1027 break;
1028 }
1029 if (spins < MAX_HEAD_SPINS)
1030 spins <<= 1;
1031 }
1032 if ((ps = p.status) == 0)
1033 U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
1034 else if (ps == CANCELLED) {
1035 if ((pp = p.prev) != null) {
1036 node.prev = pp;
1037 pp.next = node;
1038 }
1039 }
1040 else {
1041 long time; // 0 argument to park means no timeout
1042 if (deadline == 0L)
1043 time = 0L;
1044 else if ((time = deadline - System.nanoTime()) <= 0L)
1045 return cancelWaiter(node, node, false);
1046 node.thread = Thread.currentThread();
1047 if (node.prev == p && p.status == WAITING && // recheck
1048 (p != whead || (state & ABITS) != 0L))
1049 U.park(false, time);
1050 node.thread = null;
1051 if (interruptible && Thread.interrupted())
1052 return cancelWaiter(node, node, true);
1053 }
1054 }
1055 }
1056
1057 /**
1058 * See above for explanation.
1059 *
1060 * @param interruptible true if should check interrupts and if so
1061 * return INTERRUPTED
1062 * @param deadline if nonzero, the System.nanoTime value to timeout
1063 * at (and return zero)
1064 * @return next state, or INTERRUPTED
1065 */
1066 private long acquireRead(boolean interruptible, long deadline) {
1067 WNode node = null, group = null, p;
1068 for (int spins = -1;;) {
1069 for (;;) {
1070 long s, m, ns; WNode h, q; Thread w; // anti-barging guard
1071 if (group == null && (h = whead) != null &&
1072 (q = h.next) != null && q.mode != RMODE)
1073 break;
1074 if ((m = (s = state) & ABITS) < RFULL ?
1075 U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
1076 (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
1077 if (group != null) { // help release others
1078 for (WNode r = group;;) {
1079 if ((w = r.thread) != null) {
1080 r.thread = null;
1081 U.unpark(w);
1082 }
1083 if ((r = group.cowait) == null)
1084 break;
1085 U.compareAndSwapObject(group, WCOWAIT, r, r.cowait);
1086 }
1087 }
1088 return ns;
1089 }
1090 if (m >= WBIT)
1091 break;
1092 }
1093 if (spins > 0) {
1094 if (ThreadLocalRandom.current().nextInt() >= 0)
1095 --spins;
1096 }
1097 else if ((p = wtail) == null) {
1098 WNode h = new WNode(WMODE, null);
1099 if (U.compareAndSwapObject(this, WHEAD, null, h))
1100 wtail = h;
1101 }
1102 else if (spins < 0)
1103 spins = (p == whead) ? SPINS : 0;
1104 else if (node == null)
1105 node = new WNode(WMODE, p);
1106 else if (node.prev != p)
1107 node.prev = p;
1108 else if (p.mode == RMODE && p != whead) {
1109 WNode pp = p.prev; // become co-waiter with group p
1110 if (pp != null && p == wtail &&
1111 U.compareAndSwapObject(p, WCOWAIT,
1112 node.cowait = p.cowait, node)) {
1113 node.thread = Thread.currentThread();
1114 for (long time;;) {
1115 if (interruptible && Thread.interrupted())
1116 return cancelWaiter(node, p, true);
1117 if (deadline == 0L)
1118 time = 0L;
1119 else if ((time = deadline - System.nanoTime()) <= 0L)
1120 return cancelWaiter(node, p, false);
1121 if (node.thread == null)
1122 break;
1123 if (p.prev != pp || p.status == CANCELLED ||
1124 p == whead || p.prev != pp) {
1125 node.thread = null;
1126 break;
1127 }
1128 if (node.thread == null) // must recheck
1129 break;
1130 U.park(false, time);
1131 }
1132 group = p;
1133 }
1134 node = null; // throw away
1135 }
1136 else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
1137 p.next = node;
1138 break;
1139 }
1140 }
1141
1142 for (int spins = SPINS;;) {
1143 WNode np, pp, r; int ps; long m, s, ns; Thread w;
1144 while ((np = node.prev) != p && np != null)
1145 (p = np).next = node;
1146 if (whead == p) {
1147 for (int k = spins;;) {
1148 if ((m = (s = state) & ABITS) != WBIT) {
1149 if (m < RFULL ?
1150 U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT):
1151 (ns = tryIncReaderOverflow(s)) != 0L) {
1152 whead = node;
1153 node.prev = null;
1154 while ((r = node.cowait) != null) {
1155 if (U.compareAndSwapObject(node, WCOWAIT,
1156 r, r.cowait) &&
1157 (w = r.thread) != null) {
1158 r.thread = null;
1159 U.unpark(w); // release co-waiter
1160 }
1161 }
1162 return ns;
1163 }
1164 }
1165 else if (ThreadLocalRandom.current().nextInt() >= 0 &&
1166 --k <= 0)
1167 break;
1168 }
1169 if (spins < MAX_HEAD_SPINS)
1170 spins <<= 1;
1171 }
1172 if ((ps = p.status) == 0)
1173 U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
1174 else if (ps == CANCELLED) {
1175 if ((pp = p.prev) != null) {
1176 node.prev = pp;
1177 pp.next = node;
1178 }
1179 }
1180 else {
1181 long time;
1182 if (deadline == 0L)
1183 time = 0L;
1184 else if ((time = deadline - System.nanoTime()) <= 0L)
1185 return cancelWaiter(node, node, false);
1186 node.thread = Thread.currentThread();
1187 if (node.prev == p && p.status == WAITING &&
1188 (p != whead || (state & ABITS) != WBIT))
1189 U.park(false, time);
1190 node.thread = null;
1191 if (interruptible && Thread.interrupted())
1192 return cancelWaiter(node, node, true);
1193 }
1194 }
1195 }
1196
1197 /**
1198 * If node non-null, forces cancel status and unsplices it from
1199 * queue if possible and wakes up any cowaiters (of the node, or
1200 * group, as applicable), and in any case helps release current
1201 * first waiter if lock is free. (Calling with null arguments
1202 * serves as a conditional form of release, which is not currently
1203 * needed but may be needed under possible future cancellation
1204 * policies). This is a variant of cancellation methods in
1205 * AbstractQueuedSynchronizer (see its detailed explanation in AQS
1206 * internal documentation).
1207 *
1208 * @param node if nonnull, the waiter
1209 * @param group either node or the group node is cowaiting with
1210 * @param interrupted if already interrupted
1211 * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
1212 */
1213 private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
1214 if (node != null && group != null) {
1215 Thread w;
1216 node.status = CANCELLED;
1217 node.thread = null;
1218 // unsplice cancelled nodes from group
1219 for (WNode p = group, q; (q = p.cowait) != null;) {
1220 if (q.status == CANCELLED)
1221 U.compareAndSwapObject(p, WNEXT, q, q.next);
1222 else
1223 p = q;
1224 }
1225 if (group == node) {
1226 WNode r; // detach and wake up uncancelled co-waiters
1227 while ((r = node.cowait) != null) {
1228 if (U.compareAndSwapObject(node, WCOWAIT, r, r.cowait) &&
1229 (w = r.thread) != null) {
1230 r.thread = null;
1231 U.unpark(w);
1232 }
1233 }
1234 for (WNode pred = node.prev; pred != null; ) { // unsplice
1235 WNode succ, pp; // find valid successor
1236 while ((succ = node.next) == null ||
1237 succ.status == CANCELLED) {
1238 WNode q = null; // find successor the slow way
1239 for (WNode t = wtail; t != null && t != node; t = t.prev)
1240 if (t.status != CANCELLED)
1241 q = t; // don't link if succ cancelled
1242 if (succ == q || // ensure accurate successor
1243 U.compareAndSwapObject(node, WNEXT,
1244 succ, succ = q)) {
1245 if (succ == null && node == wtail)
1246 U.compareAndSwapObject(this, WTAIL, node, pred);
1247 break;
1248 }
1249 }
1250 if (pred.next == node) // unsplice pred link
1251 U.compareAndSwapObject(pred, WNEXT, node, succ);
1252 if (succ != null && (w = succ.thread) != null) {
1253 succ.thread = null;
1254 U.unpark(w); // wake up succ to observe new pred
1255 }
1256 if (pred.status != CANCELLED || (pp = pred.prev) == null)
1257 break;
1258 node.prev = pp; // repeat if new pred wrong/cancelled
1259 U.compareAndSwapObject(pp, WNEXT, pred, succ);
1260 pred = pp;
1261 }
1262 }
1263 }
1264 WNode h; // Possibly release first waiter
1265 while ((h = whead) != null) {
1266 long s; WNode q; // similar to release() but check eligibility
1267 if ((q = h.next) == null || q.status == CANCELLED) {
1268 for (WNode t = wtail; t != null && t != h; t = t.prev)
1269 if (t.status <= 0)
1270 q = t;
1271 }
1272 if (h == whead) {
1273 if (q != null && h.status == 0 &&
1274 ((s = state) & ABITS) != WBIT && // waiter is eligible
1275 (s == 0L || q.mode == RMODE))
1276 release(h);
1277 break;
1278 }
1279 }
1280 return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
1281 }
1282
1283 // Unsafe mechanics
1284 private static final sun.misc.Unsafe U;
1285 private static final long STATE;
1286 private static final long WHEAD;
1287 private static final long WTAIL;
1288 private static final long WNEXT;
1289 private static final long WSTATUS;
1290 private static final long WCOWAIT;
1291
1292 static {
1293 try {
1294 U = getUnsafe();
1295 Class<?> k = StampedLock.class;
1296 Class<?> wk = WNode.class;
1297 STATE = U.objectFieldOffset
1298 (k.getDeclaredField("state"));
1299 WHEAD = U.objectFieldOffset
1300 (k.getDeclaredField("whead"));
1301 WTAIL = U.objectFieldOffset
1302 (k.getDeclaredField("wtail"));
1303 WSTATUS = U.objectFieldOffset
1304 (wk.getDeclaredField("status"));
1305 WNEXT = U.objectFieldOffset
1306 (wk.getDeclaredField("next"));
1307 WCOWAIT = U.objectFieldOffset
1308 (wk.getDeclaredField("cowait"));
1309
1310 } catch (Exception e) {
1311 throw new Error(e);
1312 }
1313 }
1314
1315 /**
1316 * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
1317 * Replace with a simple call to Unsafe.getUnsafe when integrating
1318 * into a jdk.
1319 *
1320 * @return a sun.misc.Unsafe
1321 */
1322 private static sun.misc.Unsafe getUnsafe() {
1323 try {
1324 return sun.misc.Unsafe.getUnsafe();
1325 } catch (SecurityException tryReflectionInstead) {}
1326 try {
1327 return java.security.AccessController.doPrivileged
1328 (new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
1329 public sun.misc.Unsafe run() throws Exception {
1330 Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
1331 for (java.lang.reflect.Field f : k.getDeclaredFields()) {
1332 f.setAccessible(true);
1333 Object x = f.get(null);
1334 if (k.isInstance(x))
1335 return k.cast(x);
1336 }
1337 throw new NoSuchFieldError("the Unsafe");
1338 }});
1339 } catch (java.security.PrivilegedActionException e) {
1340 throw new RuntimeException("Could not initialize intrinsics",
1341 e.getCause());
1342 }
1343 }
1344 }