26 |
|
* in method {@link #unlockWrite} to release the lock. Untimed and |
27 |
|
* timed versions of {@code tryWriteLock} are also provided. When |
28 |
|
* the lock is held in write mode, no read locks may be obtained, |
29 |
< |
* and all observer validations will fail. </li> |
29 |
> |
* and all optimistic read validations will fail. </li> |
30 |
|
* |
31 |
|
* <li><b>Reading.</b> Method {@link #readLock} possibly blocks |
32 |
|
* waiting for non-exclusive access, returning a stamp that can be |
76 |
|
* into initial unlocked state, so they are not useful for remote |
77 |
|
* locking. |
78 |
|
* |
79 |
< |
* <p>The scheduling policy of StampedLock does not consistently prefer |
80 |
< |
* readers over writers or vice versa. |
79 |
> |
* <p>The scheduling policy of StampedLock does not consistently |
80 |
> |
* prefer readers over writers or vice versa. A zero return from any |
81 |
> |
* "try" method for acquiring or converting locks does carry any |
82 |
> |
* information about the state of the lock; a subsequent invocation |
83 |
> |
* may succeed. |
84 |
|
* |
85 |
|
* <p><b>Sample Usage.</b> The following illustrates some usage idioms |
86 |
|
* in a class that maintains simple two-dimensional points. The sample |
90 |
|
* |
91 |
|
* <pre>{@code |
92 |
|
* class Point { |
93 |
< |
* private volatile double x, y; |
93 |
> |
* private double x, y; |
94 |
|
* private final StampedLock sl = new StampedLock(); |
95 |
|
* |
96 |
|
* void move(double deltaX, double deltaY) { // an exclusively locked method |
122 |
|
* } |
123 |
|
* |
124 |
|
* double distanceFromOriginV2() { // combines code paths |
125 |
< |
* for (long stamp = sl.optimisticRead(); ; stamp = sl.readLock()) { |
125 |
> |
* for (long stamp = sl.tryOptimisticRead(); ; stamp = sl.readLock()) { |
126 |
|
* double currentX, currentY; |
127 |
|
* try { |
128 |
|
* currentX = x; |
180 |
|
* read-locked. The read count is ignored when validating |
181 |
|
* "optimistic" seqlock-reader-style stamps. Because we must use |
182 |
|
* a small finite number of bits (currently 7) for readers, a |
183 |
< |
* supplementatry reader overflow word is used when then number of |
183 |
> |
* supplementary reader overflow word is used when then number of |
184 |
|
* readers exceeds the count field. We do this by treating the max |
185 |
|
* reader count value (RBITS) as a spinlock protecting overflow |
186 |
|
* updates. |
238 |
|
private static final int NCPU = Runtime.getRuntime().availableProcessors(); |
239 |
|
|
240 |
|
/** Maximum number of retries before blocking on acquisition */ |
241 |
< |
private static final int SPINS = NCPU > 1 ? 1 << 6 : 1; |
241 |
> |
private static final int SPINS = (NCPU > 1) ? 1 << 6 : 1; |
242 |
|
|
243 |
< |
/** Maximum number of retries before re-blocking on write lock */ |
244 |
< |
private static final int MAX_HEAD_SPINS = NCPU > 1 ? 1 << 12 : 1; |
243 |
> |
/** Maximum number of retries before re-blocking */ |
244 |
> |
private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 12 : 1; |
245 |
|
|
246 |
|
/** The period for yielding when waiting for overflow spinlock */ |
247 |
|
private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1 |
306 |
|
* Exclusively acquires the lock, blocking if necessary |
307 |
|
* until available. |
308 |
|
* |
309 |
< |
* @return a stamp that can be used to unlock or convert mode. |
309 |
> |
* @return a stamp that can be used to unlock or convert mode |
310 |
|
*/ |
311 |
|
public long writeLock() { |
312 |
|
long s, next; |
332 |
|
|
333 |
|
/** |
334 |
|
* Exclusively acquires the lock if it is available within the |
335 |
< |
* given time and the current thread has not been interrupted |
335 |
> |
* given time and the current thread has not been interrupted. |
336 |
|
* |
337 |
|
* @return a stamp that can be used to unlock or convert mode, |
338 |
< |
* or zero if the lock is not available. |
338 |
> |
* or zero if the lock is not available |
339 |
|
* @throws InterruptedException if the current thread is interrupted |
340 |
< |
* before acquiring the lock. |
340 |
> |
* before acquiring the lock |
341 |
|
*/ |
342 |
|
public long tryWriteLock(long time, TimeUnit unit) |
343 |
|
throws InterruptedException { |
344 |
< |
long nanos = unit.toNanos(time); |
344 |
> |
long nanos = unit.toNanos(time); |
345 |
|
if (!Thread.interrupted()) { |
346 |
|
long s, next, deadline; |
347 |
|
if (((s = state) & ABITS) == 0L && |
361 |
|
* Exclusively acquires the lock, blocking if necessary |
362 |
|
* until available or the current thread is interrupted. |
363 |
|
* |
364 |
< |
* @return a stamp that can be used to unlock or convert mode. |
364 |
> |
* @return a stamp that can be used to unlock or convert mode |
365 |
|
* @throws InterruptedException if the current thread is interrupted |
366 |
< |
* before acquiring the lock. |
366 |
> |
* before acquiring the lock |
367 |
|
*/ |
368 |
|
public long writeLockInterruptibly() throws InterruptedException { |
369 |
|
if (!Thread.interrupted()) { |
381 |
|
* Non-exclusively acquires the lock, blocking if necessary |
382 |
|
* until available. |
383 |
|
* |
384 |
< |
* @return a stamp that can be used to unlock or convert mode. |
384 |
> |
* @return a stamp that can be used to unlock or convert mode |
385 |
|
*/ |
386 |
|
public long readLock() { |
387 |
|
for (;;) { |
404 |
|
* Non-exclusively acquires the lock if it is immediately available. |
405 |
|
* |
406 |
|
* @return a stamp that can be used to unlock or convert mode, |
407 |
< |
* or zero if the lock is not available. |
407 |
> |
* or zero if the lock is not available |
408 |
|
*/ |
409 |
|
public long tryReadLock() { |
410 |
|
for (;;) { |
422 |
|
|
423 |
|
/** |
424 |
|
* Non-exclusively acquires the lock if it is available within the |
425 |
< |
* given time and the current thread has not been interrupted |
425 |
> |
* given time and the current thread has not been interrupted. |
426 |
|
* |
427 |
|
* @return a stamp that can be used to unlock or convert mode, |
428 |
< |
* or zero if the lock is not available. |
428 |
> |
* or zero if the lock is not available |
429 |
|
* @throws InterruptedException if the current thread is interrupted |
430 |
< |
* before acquiring the lock. |
430 |
> |
* before acquiring the lock |
431 |
|
*/ |
432 |
|
public long tryReadLock(long time, TimeUnit unit) |
433 |
|
throws InterruptedException { |
460 |
|
* Non-exclusively acquires the lock, blocking if necessary |
461 |
|
* until available or the current thread is interrupted. |
462 |
|
* |
463 |
< |
* @return a stamp that can be used to unlock or convert mode. |
463 |
> |
* @return a stamp that can be used to unlock or convert mode |
464 |
|
* @throws InterruptedException if the current thread is interrupted |
465 |
< |
* before acquiring the lock. |
465 |
> |
* before acquiring the lock |
466 |
|
*/ |
467 |
|
public long readLockInterruptibly() throws InterruptedException { |
468 |
|
if (!Thread.interrupted()) { |
515 |
|
* |
516 |
|
* @param stamp a stamp returned by a write-lock operation |
517 |
|
* @throws IllegalMonitorStateException if the stamp does |
518 |
< |
* not match the current state of this lock. |
518 |
> |
* not match the current state of this lock |
519 |
|
*/ |
520 |
|
public void unlockWrite(long stamp) { |
521 |
|
if (state != stamp || (stamp & WBIT) == 0L) |
530 |
|
* |
531 |
|
* @param stamp a stamp returned by a read-lock operation |
532 |
|
* @throws IllegalMonitorStateException if the stamp does |
533 |
< |
* not match the current state of this lock. |
533 |
> |
* not match the current state of this lock |
534 |
|
*/ |
535 |
|
public void unlockRead(long stamp) { |
536 |
|
long s, m; |
560 |
|
* |
561 |
|
* @param stamp a stamp returned by a lock operation |
562 |
|
* @throws IllegalMonitorStateException if the stamp does |
563 |
< |
* not match the current state of this lock. |
563 |
> |
* not match the current state of this lock |
564 |
|
*/ |
565 |
|
public void unlock(long stamp) { |
566 |
|
long a = stamp & ABITS, m, s; |
676 |
|
*/ |
677 |
|
public long tryConvertToOptimisticRead(long stamp) { |
678 |
|
long a = stamp & ABITS, m, s, next; |
679 |
< |
while (((s = U.getLongVolatile(this, STATE)) & |
679 |
> |
while (((s = U.getLongVolatile(this, STATE)) & |
680 |
|
SBITS) == (stamp & SBITS)) { |
681 |
|
if ((m = s & ABITS) == 0L) { |
682 |
|
if (a != 0L) |
710 |
|
* stamp value. This method may be useful for recovery after |
711 |
|
* errors. |
712 |
|
* |
713 |
< |
* @return true if the lock was held, else false. |
713 |
> |
* @return true if the lock was held, else false |
714 |
|
*/ |
715 |
|
public boolean tryUnlockWrite() { |
716 |
|
long s; |
727 |
|
* requiring a stamp value. This method may be useful for recovery |
728 |
|
* after errors. |
729 |
|
* |
730 |
< |
* @return true if the read lock was held, else false. |
730 |
> |
* @return true if the read lock was held, else false |
731 |
|
*/ |
732 |
|
public boolean tryUnlockRead() { |
733 |
|
long s, m; |
776 |
|
* Tries to increment readerOverflow by first setting state |
777 |
|
* access bits value to RBITS, indicating hold of spinlock, |
778 |
|
* then updating, then releasing. |
779 |
+ |
* |
780 |
|
* @param stamp, assumed that (stamp & ABITS) >= RFULL |
781 |
|
* @return new stamp on success, else zero |
782 |
|
*/ |
788 |
|
return s; |
789 |
|
} |
790 |
|
} |
791 |
< |
else if ((ThreadLocalRandom.current().nextInt() & |
791 |
> |
else if ((ThreadLocalRandom.current().nextInt() & |
792 |
|
OVERFLOW_YIELD_RATE) == 0) |
793 |
|
Thread.yield(); |
794 |
|
return 0L; |
796 |
|
|
797 |
|
/** |
798 |
|
* Tries to decrement readerOverflow. |
799 |
+ |
* |
800 |
|
* @param stamp, assumed that (stamp & ABITS) >= RFULL |
801 |
|
* @return new stamp on success, else zero |
802 |
|
*/ |
814 |
|
return next; |
815 |
|
} |
816 |
|
} |
817 |
< |
else if ((ThreadLocalRandom.current().nextInt() & |
817 |
> |
else if ((ThreadLocalRandom.current().nextInt() & |
818 |
|
OVERFLOW_YIELD_RATE) == 0) |
819 |
|
Thread.yield(); |
820 |
|
return 0L; |
916 |
|
|
917 |
|
/** |
918 |
|
* Possibly spins trying to obtain write lock, then enqueues and |
919 |
< |
* blocks while not head of write queue or cannot aquire lock, |
919 |
> |
* blocks while not head of write queue or cannot acquire lock, |
920 |
|
* possibly spinning when at head; cancelling on timeout or |
921 |
|
* interrupt. |
922 |
|
* |
923 |
|
* @param interruptible true if should check interrupts and if so |
924 |
|
* return INTERRUPTED |
925 |
|
* @param deadline if nonzero, the System.nanoTime value to timeout |
926 |
< |
* at (and return zero). |
926 |
> |
* at (and return zero) |
927 |
|
*/ |
928 |
|
private long awaitWrite(boolean interruptible, long deadline) { |
929 |
|
WNode node = null; |
1024 |
|
} |
1025 |
|
} |
1026 |
|
writerPrefSignal(); |
1027 |
< |
return (interrupted || Thread.interrupted())? INTERRUPTED : 0L; |
1027 |
> |
return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L; |
1028 |
|
} |
1029 |
|
|
1030 |
< |
/* |
1030 |
> |
/** |
1031 |
|
* Waits for read lock or timeout or interrupt. The form of |
1032 |
|
* awaitRead differs from awaitWrite mainly because it must |
1033 |
|
* restart (with a new wait node) if the thread was unqueued and |
1106 |
|
/** |
1107 |
|
* If node non-null, forces cancel status and unsplices from queue |
1108 |
|
* if possible, by traversing entire queue looking for cancelled |
1109 |
< |
* nodes, cleaning out all at head, but stopping upon first |
1105 |
< |
* encounter otherwise. |
1109 |
> |
* nodes. |
1110 |
|
*/ |
1111 |
|
private long cancelReader(RNode node, boolean interrupted) { |
1112 |
|
Thread w; |
1121 |
|
} |
1122 |
|
else { |
1123 |
|
U.compareAndSwapObject(pred, RNEXT, p, q); |
1124 |
< |
break; |
1124 |
> |
p = pred.next; |
1125 |
|
} |
1126 |
|
} |
1127 |
|
else { |
1131 |
|
} |
1132 |
|
} |
1133 |
|
readerPrefSignal(); |
1134 |
< |
return (interrupted || Thread.interrupted())? INTERRUPTED : 0L; |
1134 |
> |
return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L; |
1135 |
|
} |
1136 |
|
|
1137 |
|
// Unsafe mechanics |
1205 |
|
} |
1206 |
|
|
1207 |
|
} |
1204 |
– |
|