7 |
|
|
8 |
|
import static java.util.concurrent.TimeUnit.DAYS; |
9 |
|
import static java.util.concurrent.TimeUnit.MILLISECONDS; |
10 |
– |
import static java.util.concurrent.TimeUnit.SECONDS; |
10 |
|
|
11 |
|
import java.util.ArrayList; |
12 |
|
import java.util.List; |
247 |
|
long s = assertNonZero(lock.writeLock()); |
248 |
|
assertTrue(lock.validate(s)); |
249 |
|
assertFalse(lock.validate(lock.tryWriteLock())); |
250 |
< |
assertFalse(lock.validate(lock.tryWriteLock(0L, SECONDS))); |
250 |
> |
assertFalse(lock.validate(lock.tryWriteLock(randomExpiredTimeout(), |
251 |
> |
randomTimeUnit()))); |
252 |
|
assertFalse(lock.validate(lock.tryReadLock())); |
253 |
< |
assertFalse(lock.validate(lock.tryReadLock(0L, SECONDS))); |
253 |
> |
assertFalse(lock.validate(lock.tryWriteLock(randomExpiredTimeout(), |
254 |
> |
randomTimeUnit()))); |
255 |
|
assertFalse(lock.validate(lock.tryOptimisticRead())); |
256 |
|
lock.unlockWrite(s); |
257 |
|
} |
273 |
|
* interruptible operations throw InterruptedException when pre-interrupted |
274 |
|
*/ |
275 |
|
public void testInterruptibleOperationsThrowInterruptedExceptionWhenPreInterrupted() { |
275 |
– |
final CountDownLatch running = new CountDownLatch(1); |
276 |
|
final StampedLock lock = new StampedLock(); |
277 |
|
|
278 |
|
Action[] interruptibleLockActions = { |
337 |
|
* interruptible operations throw InterruptedException when write locked and interrupted |
338 |
|
*/ |
339 |
|
public void testInterruptibleOperationsThrowInterruptedExceptionWriteLockedInterrupted() { |
340 |
– |
final CountDownLatch running = new CountDownLatch(1); |
340 |
|
final StampedLock lock = new StampedLock(); |
341 |
|
long s = lock.writeLock(); |
342 |
|
|
359 |
|
* interruptible operations throw InterruptedException when read locked and interrupted |
360 |
|
*/ |
361 |
|
public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() { |
363 |
– |
final CountDownLatch running = new CountDownLatch(1); |
362 |
|
final StampedLock lock = new StampedLock(); |
363 |
|
long s = lock.readLock(); |
364 |
|
|
477 |
|
} |
478 |
|
|
479 |
|
/** |
480 |
< |
* A writelock succeeds only after a reading thread unlocks |
480 |
> |
* writeLock() succeeds only after a reading thread unlocks |
481 |
|
*/ |
482 |
|
public void testWriteAfterReadLock() throws InterruptedException { |
483 |
< |
final CountDownLatch running = new CountDownLatch(1); |
483 |
> |
final CountDownLatch aboutToLock = new CountDownLatch(1); |
484 |
|
final StampedLock lock = new StampedLock(); |
485 |
|
long rs = lock.readLock(); |
486 |
|
Thread t = newStartedThread(new CheckedRunnable() { |
487 |
|
public void realRun() { |
488 |
< |
running.countDown(); |
488 |
> |
aboutToLock.countDown(); |
489 |
|
long s = lock.writeLock(); |
490 |
+ |
assertTrue(lock.isWriteLocked()); |
491 |
+ |
assertFalse(lock.isReadLocked()); |
492 |
|
lock.unlockWrite(s); |
493 |
|
}}); |
494 |
|
|
495 |
< |
running.await(); |
496 |
< |
waitForThreadToEnterWaitState(t, MEDIUM_DELAY_MS); |
495 |
> |
await(aboutToLock); |
496 |
> |
assertThreadBlocks(t, Thread.State.WAITING); |
497 |
|
assertFalse(lock.isWriteLocked()); |
498 |
+ |
assertTrue(lock.isReadLocked()); |
499 |
|
lock.unlockRead(rs); |
500 |
|
awaitTermination(t); |
501 |
< |
assertFalse(lock.isWriteLocked()); |
501 |
> |
assertUnlocked(lock); |
502 |
|
} |
503 |
|
|
504 |
|
/** |
505 |
< |
* A writelock succeeds only after reading threads unlock |
505 |
> |
* writeLock() succeeds only after reading threads unlock |
506 |
|
*/ |
507 |
|
public void testWriteAfterMultipleReadLocks() { |
508 |
|
final StampedLock lock = new StampedLock(); |
525 |
|
assertFalse(lock.isWriteLocked()); |
526 |
|
lock.unlockRead(s); |
527 |
|
awaitTermination(t2); |
528 |
< |
assertFalse(lock.isWriteLocked()); |
528 |
> |
assertUnlocked(lock); |
529 |
|
} |
530 |
|
|
531 |
|
/** |
532 |
< |
* Readlocks succeed only after a writing thread unlocks |
532 |
> |
* readLock() succeed only after a writing thread unlocks |
533 |
|
*/ |
534 |
|
public void testReadAfterWriteLock() { |
535 |
|
final StampedLock lock = new StampedLock(); |
536 |
|
final CountDownLatch threadsStarted = new CountDownLatch(2); |
537 |
|
final long s = lock.writeLock(); |
538 |
< |
Thread t1 = newStartedThread(new CheckedRunnable() { |
538 |
< |
public void realRun() { |
539 |
< |
threadsStarted.countDown(); |
540 |
< |
long rs = lock.readLock(); |
541 |
< |
lock.unlockRead(rs); |
542 |
< |
}}); |
543 |
< |
Thread t2 = newStartedThread(new CheckedRunnable() { |
538 |
> |
final Runnable acquireReleaseReadLock = new CheckedRunnable() { |
539 |
|
public void realRun() { |
540 |
|
threadsStarted.countDown(); |
541 |
|
long rs = lock.readLock(); |
542 |
+ |
assertTrue(lock.isReadLocked()); |
543 |
+ |
assertFalse(lock.isWriteLocked()); |
544 |
|
lock.unlockRead(rs); |
545 |
< |
}}); |
545 |
> |
}}; |
546 |
> |
Thread t1 = newStartedThread(acquireReleaseReadLock); |
547 |
> |
Thread t2 = newStartedThread(acquireReleaseReadLock); |
548 |
|
|
549 |
|
await(threadsStarted); |
550 |
< |
waitForThreadToEnterWaitState(t1, MEDIUM_DELAY_MS); |
551 |
< |
waitForThreadToEnterWaitState(t2, MEDIUM_DELAY_MS); |
550 |
> |
assertThreadBlocks(t1, Thread.State.WAITING); |
551 |
> |
assertThreadBlocks(t2, Thread.State.WAITING); |
552 |
> |
assertTrue(lock.isWriteLocked()); |
553 |
> |
assertFalse(lock.isReadLocked()); |
554 |
|
releaseWriteLock(lock, s); |
555 |
|
awaitTermination(t1); |
556 |
|
awaitTermination(t2); |
557 |
+ |
assertUnlocked(lock); |
558 |
|
} |
559 |
|
|
560 |
|
/** |
740 |
|
*/ |
741 |
|
public void testValidateOptimisticWriteLocked2() |
742 |
|
throws InterruptedException { |
743 |
< |
final CountDownLatch running = new CountDownLatch(1); |
743 |
> |
final CountDownLatch locked = new CountDownLatch(1); |
744 |
|
final StampedLock lock = new StampedLock(); |
745 |
|
final long p = assertValid(lock, lock.tryOptimisticRead()); |
746 |
|
|
747 |
|
Thread t = newStartedThread(new CheckedInterruptedRunnable() { |
748 |
|
public void realRun() throws InterruptedException { |
749 |
|
lock.writeLockInterruptibly(); |
750 |
< |
running.countDown(); |
750 |
> |
locked.countDown(); |
751 |
|
lock.writeLockInterruptibly(); |
752 |
|
}}); |
753 |
|
|
754 |
< |
running.await(); |
754 |
> |
await(locked); |
755 |
|
assertFalse(lock.validate(p)); |
756 |
|
assertEquals(0L, lock.tryOptimisticRead()); |
757 |
+ |
assertThreadBlocks(t, Thread.State.WAITING); |
758 |
|
t.interrupt(); |
759 |
|
awaitTermination(t); |
760 |
+ |
assertTrue(lock.isWriteLocked()); |
761 |
|
} |
762 |
|
|
763 |
|
/** |
1180 |
|
} |
1181 |
|
assertUnlocked(lock); |
1182 |
|
} |
1183 |
+ |
|
1184 |
+ |
/** |
1185 |
+ |
* Stamped locks are not reentrant. |
1186 |
+ |
*/ |
1187 |
+ |
public void testNonReentrant() throws InterruptedException { |
1188 |
+ |
final StampedLock lock = new StampedLock(); |
1189 |
+ |
long stamp; |
1190 |
+ |
|
1191 |
+ |
stamp = lock.writeLock(); |
1192 |
+ |
assertValid(lock, stamp); |
1193 |
+ |
assertEquals(0L, lock.tryWriteLock(0L, DAYS)); |
1194 |
+ |
assertEquals(0L, lock.tryReadLock(0L, DAYS)); |
1195 |
+ |
assertValid(lock, stamp); |
1196 |
+ |
lock.unlockWrite(stamp); |
1197 |
+ |
|
1198 |
+ |
stamp = lock.tryWriteLock(1L, DAYS); |
1199 |
+ |
assertEquals(0L, lock.tryWriteLock(0L, DAYS)); |
1200 |
+ |
assertValid(lock, stamp); |
1201 |
+ |
lock.unlockWrite(stamp); |
1202 |
+ |
|
1203 |
+ |
stamp = lock.readLock(); |
1204 |
+ |
assertEquals(0L, lock.tryWriteLock(0L, DAYS)); |
1205 |
+ |
assertValid(lock, stamp); |
1206 |
+ |
lock.unlockRead(stamp); |
1207 |
+ |
} |
1208 |
+ |
|
1209 |
+ |
/** |
1210 |
+ |
* """StampedLocks have no notion of ownership. Locks acquired in |
1211 |
+ |
* one thread can be released or converted in another.""" |
1212 |
+ |
*/ |
1213 |
+ |
public void testNoOwnership() throws Throwable { |
1214 |
+ |
ArrayList<Future<?>> futures = new ArrayList<>(); |
1215 |
+ |
for (Function<StampedLock, Long> writeLocker : writeLockers()) |
1216 |
+ |
for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { |
1217 |
+ |
StampedLock lock = new StampedLock(); |
1218 |
+ |
long stamp = writeLocker.apply(lock); |
1219 |
+ |
futures.add(cachedThreadPool.submit(new CheckedRunnable() { |
1220 |
+ |
public void realRun() { |
1221 |
+ |
writeUnlocker.accept(lock, stamp); |
1222 |
+ |
assertUnlocked(lock); |
1223 |
+ |
assertFalse(lock.validate(stamp)); |
1224 |
+ |
}})); |
1225 |
+ |
} |
1226 |
+ |
for (Future<?> future : futures) |
1227 |
+ |
assertNull(future.get()); |
1228 |
+ |
} |
1229 |
|
} |