--- jsr166/src/test/tck/ReentrantReadWriteLockTest.java 2018/01/23 20:44:11 1.82 +++ jsr166/src/test/tck/ReentrantReadWriteLockTest.java 2019/09/22 01:59:57 1.83 @@ -11,6 +11,7 @@ import static java.util.concurrent.TimeU import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Condition; @@ -1680,4 +1681,64 @@ public class ReentrantReadWriteLockTest assertTrue(lock.writeLock().toString().contains("Unlocked")); } + /** + * ThreadMXBean reports the blockers that we expect. + */ + public void testBlockers() { + if (!testImplementationDetails) return; + final boolean fair = randomBoolean(); + final boolean timedAcquire = randomBoolean(); + final boolean timedAwait = randomBoolean(); + final String syncClassName = fair + ? "ReentrantReadWriteLock$FairSync" + : "ReentrantReadWriteLock$NonfairSync"; + final String conditionClassName + = "AbstractQueuedSynchronizer$ConditionObject"; + final Thread.State expectedAcquireState = timedAcquire + ? Thread.State.TIMED_WAITING + : Thread.State.WAITING; + final Thread.State expectedAwaitState = timedAwait + ? Thread.State.TIMED_WAITING + : Thread.State.WAITING; + final Lock lock = new ReentrantReadWriteLock(fair).writeLock(); + final Condition condition = lock.newCondition(); + final AtomicBoolean conditionSatisfied = new AtomicBoolean(false); + lock.lock(); + final Thread thread = newStartedThread((Action) () -> { + if (timedAcquire) + lock.tryLock(LONGER_DELAY_MS, MILLISECONDS); + else + lock.lock(); + while (!conditionSatisfied.get()) + if (timedAwait) + condition.await(LONGER_DELAY_MS, MILLISECONDS); + else + condition.await(); + }); + Callable waitingForLock = () -> { + String className; + return thread.getState() == expectedAcquireState + && (className = blockerClassName(thread)) != null + && className.endsWith(syncClassName); + }; + waitForThreadToEnterWaitState(thread, waitingForLock); + + lock.unlock(); + Callable waitingForCondition = () -> { + String className; + return thread.getState() == expectedAwaitState + && (className = blockerClassName(thread)) != null + && className.endsWith(conditionClassName); + }; + waitForThreadToEnterWaitState(thread, waitingForCondition); + + // politely release the waiter + conditionSatisfied.set(true); + lock.lock(); + try { + condition.signal(); + } finally { lock.unlock(); } + + awaitTermination(thread); + } }