ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/ReentrantLockTest.java
(Generate patch)

Comparing jsr166/src/test/tck/ReentrantLockTest.java (file contents):
Revision 1.48 by jsr166, Sat May 21 06:24:33 2011 UTC vs.
Revision 1.70 by jsr166, Sun Sep 22 01:59:57 2019 UTC

# Line 6 | Line 6
6   * Pat Fisher, Mike Judd.
7   */
8  
9 import junit.framework.*;
10 import java.util.concurrent.locks.*;
11 import java.util.concurrent.*;
9   import static java.util.concurrent.TimeUnit.MILLISECONDS;
13 import java.util.*;
14 import java.io.*;
10  
11 + import java.util.ArrayList;
12 + import java.util.Arrays;
13 + import java.util.Collection;
14 + import java.util.HashSet;
15 + import java.util.concurrent.Callable;
16 + import java.util.concurrent.CountDownLatch;
17 + import java.util.concurrent.CyclicBarrier;
18 + import java.util.concurrent.ThreadLocalRandom;
19 + import java.util.concurrent.atomic.AtomicBoolean;
20 + import java.util.concurrent.locks.Condition;
21 + import java.util.concurrent.locks.Lock;
22 + import java.util.concurrent.locks.ReentrantLock;
23 +
24 + import junit.framework.Test;
25 + import junit.framework.TestSuite;
26 +
27 + @SuppressWarnings("WaitNotInLoop") // we implement spurious-wakeup freedom
28   public class ReentrantLockTest extends JSR166TestCase {
29      public static void main(String[] args) {
30 <        junit.textui.TestRunner.run(suite());
30 >        main(suite(), args);
31      }
32      public static Test suite() {
33          return new TestSuite(ReentrantLockTest.class);
34      }
35  
36      /**
37 <     * A runnable calling lockInterruptibly
37 >     * A checked runnable calling lockInterruptibly
38       */
39      class InterruptibleLockRunnable extends CheckedRunnable {
40          final ReentrantLock lock;
41 <        InterruptibleLockRunnable(ReentrantLock l) { lock = l; }
41 >        InterruptibleLockRunnable(ReentrantLock lock) { this.lock = lock; }
42          public void realRun() throws InterruptedException {
43              lock.lockInterruptibly();
44          }
45      }
46  
47      /**
48 <     * A runnable calling lockInterruptibly that expects to be
48 >     * A checked runnable calling lockInterruptibly that expects to be
49       * interrupted
50       */
51      class InterruptedLockRunnable extends CheckedInterruptedRunnable {
52          final ReentrantLock lock;
53 <        InterruptedLockRunnable(ReentrantLock l) { lock = l; }
53 >        InterruptedLockRunnable(ReentrantLock lock) { this.lock = lock; }
54          public void realRun() throws InterruptedException {
55              lock.lockInterruptibly();
56          }
# Line 78 | Line 90 | public class ReentrantLockTest extends J
90          long startTime = System.nanoTime();
91          while (!lock.hasQueuedThread(t)) {
92              if (millisElapsedSince(startTime) > LONG_DELAY_MS)
93 <                throw new AssertionFailedError("timed out");
93 >                throw new AssertionError("timed out");
94              Thread.yield();
95          }
96          assertTrue(t.isAlive());
97 <        assertTrue(lock.getOwner() != t);
97 >        assertNotSame(t, lock.getOwner());
98      }
99  
100      /**
# Line 136 | Line 148 | public class ReentrantLockTest extends J
148          lock.unlock();
149      }
150  
151 <    enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil };
151 >    enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil }
152 >
153 >    static AwaitMethod randomAwaitMethod() {
154 >        AwaitMethod[] awaitMethods = AwaitMethod.values();
155 >        return awaitMethods[ThreadLocalRandom.current().nextInt(awaitMethods.length)];
156 >    }
157  
158      /**
159 <     * Awaits condition using the specified AwaitMethod.
159 >     * Awaits condition "indefinitely" using the specified AwaitMethod.
160       */
161      void await(Condition c, AwaitMethod awaitMethod)
162              throws InterruptedException {
# Line 152 | Line 169 | public class ReentrantLockTest extends J
169              assertTrue(c.await(timeoutMillis, MILLISECONDS));
170              break;
171          case awaitNanos:
172 <            long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
173 <            long nanosRemaining = c.awaitNanos(nanosTimeout);
174 <            assertTrue(nanosRemaining > 0);
172 >            long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis);
173 >            long nanosRemaining = c.awaitNanos(timeoutNanos);
174 >            assertTrue(nanosRemaining > timeoutNanos / 2);
175 >            assertTrue(nanosRemaining <= timeoutNanos);
176              break;
177          case awaitUntil:
178              assertTrue(c.awaitUntil(delayedDate(timeoutMillis)));
179              break;
180 +        default:
181 +            throw new AssertionError();
182          }
183      }
184  
# Line 199 | Line 219 | public class ReentrantLockTest extends J
219      public void testUnlock_IMSE()      { testUnlock_IMSE(false); }
220      public void testUnlock_IMSE_fair() { testUnlock_IMSE(true); }
221      public void testUnlock_IMSE(boolean fair) {
222 <        ReentrantLock lock = new ReentrantLock(fair);
222 >        final ReentrantLock lock = new ReentrantLock(fair);
223          try {
224              lock.unlock();
225              shouldThrow();
# Line 286 | Line 306 | public class ReentrantLockTest extends J
306      }
307  
308      /**
309 <     * hasQueuedThread reports whether a thread is queued.
309 >     * hasQueuedThread reports whether a thread is queued
310       */
311      public void testHasQueuedThread()      { testHasQueuedThread(false); }
312      public void testHasQueuedThread_fair() { testHasQueuedThread(true); }
# Line 347 | Line 367 | public class ReentrantLockTest extends J
367      }
368  
369      /**
370 <     * timed tryLock is interruptible.
370 >     * timed tryLock is interruptible
371       */
372      public void testTryLock_Interruptible()      { testTryLock_Interruptible(false); }
373      public void testTryLock_Interruptible_fair() { testTryLock_Interruptible(true); }
# Line 389 | Line 409 | public class ReentrantLockTest extends J
409      public void testTryLock_Timeout_fair() { testTryLock_Timeout(true); }
410      public void testTryLock_Timeout(boolean fair) {
411          final PublicReentrantLock lock = new PublicReentrantLock(fair);
412 +        final long timeoutMillis = timeoutMillis();
413          lock.lock();
414          Thread t = newStartedThread(new CheckedRunnable() {
415              public void realRun() throws InterruptedException {
416                  long startTime = System.nanoTime();
396                long timeoutMillis = 10;
417                  assertFalse(lock.tryLock(timeoutMillis, MILLISECONDS));
418                  assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
419              }});
# Line 408 | Line 428 | public class ReentrantLockTest extends J
428      public void testGetHoldCount()      { testGetHoldCount(false); }
429      public void testGetHoldCount_fair() { testGetHoldCount(true); }
430      public void testGetHoldCount(boolean fair) {
431 <        ReentrantLock lock = new ReentrantLock(fair);
431 >        final ReentrantLock lock = new ReentrantLock(fair);
432          for (int i = 1; i <= SIZE; i++) {
433              lock.lock();
434              assertEquals(i, lock.getHoldCount());
435          }
436          for (int i = SIZE; i > 0; i--) {
437              lock.unlock();
438 <            assertEquals(i-1, lock.getHoldCount());
438 >            assertEquals(i - 1, lock.getHoldCount());
439          }
440      }
441  
# Line 425 | Line 445 | public class ReentrantLockTest extends J
445      public void testIsLocked()      { testIsLocked(false); }
446      public void testIsLocked_fair() { testIsLocked(true); }
447      public void testIsLocked(boolean fair) {
448 +        final ReentrantLock lock = new ReentrantLock(fair);
449          try {
429            final ReentrantLock lock = new ReentrantLock(fair);
450              assertFalse(lock.isLocked());
451              lock.lock();
452              assertTrue(lock.isLocked());
# Line 451 | Line 471 | public class ReentrantLockTest extends J
471              barrier.await();
472              awaitTermination(t);
473              assertFalse(lock.isLocked());
474 <        } catch (Exception e) {
455 <            threadUnexpectedException(e);
456 <        }
474 >        } catch (Exception fail) { threadUnexpectedException(fail); }
475      }
476  
477      /**
# Line 465 | Line 483 | public class ReentrantLockTest extends J
483          final PublicReentrantLock lock = new PublicReentrantLock(fair);
484          try {
485              lock.lockInterruptibly();
486 <        } catch (InterruptedException ie) {
469 <            threadUnexpectedException(ie);
470 <        }
486 >        } catch (InterruptedException fail) { threadUnexpectedException(fail); }
487          assertLockedByMoi(lock);
488          Thread t = newStartedThread(new InterruptedLockRunnable(lock));
489          waitForQueuedThread(lock, t);
# Line 517 | Line 533 | public class ReentrantLockTest extends J
533      public void testAwaitNanos_Timeout()      { testAwaitNanos_Timeout(false); }
534      public void testAwaitNanos_Timeout_fair() { testAwaitNanos_Timeout(true); }
535      public void testAwaitNanos_Timeout(boolean fair) {
536 +        final ReentrantLock lock = new ReentrantLock(fair);
537 +        final Condition c = lock.newCondition();
538 +        final long timeoutMillis = timeoutMillis();
539 +        final long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis);
540 +        lock.lock();
541 +        final long startTime = System.nanoTime();
542          try {
521            final ReentrantLock lock = new ReentrantLock(fair);
522            final Condition c = lock.newCondition();
523            lock.lock();
524            long startTime = System.nanoTime();
525            long timeoutMillis = 10;
526            long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis);
543              long nanosRemaining = c.awaitNanos(timeoutNanos);
544              assertTrue(nanosRemaining <= 0);
545 <            assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
546 <            lock.unlock();
547 <        } catch (InterruptedException e) {
532 <            threadUnexpectedException(e);
533 <        }
545 >        } catch (InterruptedException fail) { threadUnexpectedException(fail); }
546 >        assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
547 >        lock.unlock();
548      }
549  
550      /**
# Line 539 | Line 553 | public class ReentrantLockTest extends J
553      public void testAwait_Timeout()      { testAwait_Timeout(false); }
554      public void testAwait_Timeout_fair() { testAwait_Timeout(true); }
555      public void testAwait_Timeout(boolean fair) {
556 +        final ReentrantLock lock = new ReentrantLock(fair);
557 +        final Condition c = lock.newCondition();
558 +        final long timeoutMillis = timeoutMillis();
559 +        lock.lock();
560 +        final long startTime = System.nanoTime();
561          try {
543            final ReentrantLock lock = new ReentrantLock(fair);
544            final Condition c = lock.newCondition();
545            lock.lock();
546            long startTime = System.nanoTime();
547            long timeoutMillis = 10;
562              assertFalse(c.await(timeoutMillis, MILLISECONDS));
563 <            assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
564 <            lock.unlock();
565 <        } catch (InterruptedException e) {
552 <            threadUnexpectedException(e);
553 <        }
563 >        } catch (InterruptedException fail) { threadUnexpectedException(fail); }
564 >        assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
565 >        lock.unlock();
566      }
567  
568      /**
# Line 559 | Line 571 | public class ReentrantLockTest extends J
571      public void testAwaitUntil_Timeout()      { testAwaitUntil_Timeout(false); }
572      public void testAwaitUntil_Timeout_fair() { testAwaitUntil_Timeout(true); }
573      public void testAwaitUntil_Timeout(boolean fair) {
574 +        final ReentrantLock lock = new ReentrantLock(fair);
575 +        final Condition c = lock.newCondition();
576 +        lock.lock();
577 +        // We shouldn't assume that nanoTime and currentTimeMillis
578 +        // use the same time source, so don't use nanoTime here.
579 +        final java.util.Date delayedDate = delayedDate(timeoutMillis());
580          try {
581 <            final ReentrantLock lock = new ReentrantLock(fair);
582 <            final Condition c = lock.newCondition();
583 <            lock.lock();
584 <            long startTime = System.nanoTime();
567 <            long timeoutMillis = 10;
568 <            java.util.Date d = new java.util.Date();
569 <            assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + timeoutMillis)));
570 <            assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
571 <            lock.unlock();
572 <        } catch (InterruptedException e) {
573 <            threadUnexpectedException(e);
574 <        }
581 >            assertFalse(c.awaitUntil(delayedDate));
582 >        } catch (InterruptedException fail) { threadUnexpectedException(fail); }
583 >        assertTrue(new java.util.Date().getTime() >= delayedDate.getTime());
584 >        lock.unlock();
585      }
586  
587      /**
# Line 735 | Line 745 | public class ReentrantLockTest extends J
745      public void testHasWaiters(boolean fair) {
746          final PublicReentrantLock lock = new PublicReentrantLock(fair);
747          final Condition c = lock.newCondition();
748 <        final CountDownLatch locked = new CountDownLatch(1);
748 >        final CountDownLatch pleaseSignal = new CountDownLatch(1);
749          Thread t = newStartedThread(new CheckedRunnable() {
750              public void realRun() throws InterruptedException {
751                  lock.lock();
752                  assertHasNoWaiters(lock, c);
753                  assertFalse(lock.hasWaiters(c));
754 <                locked.countDown();
754 >                pleaseSignal.countDown();
755                  c.await();
756                  assertHasNoWaiters(lock, c);
757                  assertFalse(lock.hasWaiters(c));
758                  lock.unlock();
759              }});
760  
761 <        await(locked);
761 >        await(pleaseSignal);
762          lock.lock();
763          assertHasWaiters(lock, c, t);
764          assertTrue(lock.hasWaiters(c));
# Line 879 | Line 889 | public class ReentrantLockTest extends J
889      }
890  
891      /**
892 <     * awaitUninterruptibly doesn't abort on interrupt
892 >     * awaitUninterruptibly is uninterruptible
893       */
894      public void testAwaitUninterruptibly()      { testAwaitUninterruptibly(false); }
895      public void testAwaitUninterruptibly_fair() { testAwaitUninterruptibly(true); }
896      public void testAwaitUninterruptibly(boolean fair) {
897          final ReentrantLock lock = new ReentrantLock(fair);
898 <        final Condition c = lock.newCondition();
899 <        final CountDownLatch locked = new CountDownLatch(1);
900 <        Thread t = newStartedThread(new CheckedRunnable() {
898 >        final Condition condition = lock.newCondition();
899 >        final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
900 >
901 >        Thread t1 = newStartedThread(new CheckedRunnable() {
902              public void realRun() {
903 +                // Interrupt before awaitUninterruptibly
904                  lock.lock();
905 <                locked.countDown();
906 <                c.awaitUninterruptibly();
905 >                pleaseInterrupt.countDown();
906 >                Thread.currentThread().interrupt();
907 >                condition.awaitUninterruptibly();
908                  assertTrue(Thread.interrupted());
909                  lock.unlock();
910              }});
911  
912 <        await(locked);
912 >        Thread t2 = newStartedThread(new CheckedRunnable() {
913 >            public void realRun() {
914 >                // Interrupt during awaitUninterruptibly
915 >                lock.lock();
916 >                pleaseInterrupt.countDown();
917 >                condition.awaitUninterruptibly();
918 >                assertTrue(Thread.interrupted());
919 >                lock.unlock();
920 >            }});
921 >
922 >        await(pleaseInterrupt);
923 >        t2.interrupt();
924          lock.lock();
925          lock.unlock();
926 <        t.interrupt();
927 <        long timeoutMillis = 10;
928 <        assertThreadStaysAlive(t, timeoutMillis);
926 >        assertThreadBlocks(t1, Thread.State.WAITING);
927 >        assertThreadBlocks(t2, Thread.State.WAITING);
928 >
929          lock.lock();
930 <        c.signal();
930 >        condition.signalAll();
931          lock.unlock();
932 <        awaitTermination(t);
932 >
933 >        awaitTermination(t1);
934 >        awaitTermination(t2);
935      }
936  
937      /**
# Line 923 | Line 949 | public class ReentrantLockTest extends J
949          final PublicReentrantLock lock =
950              new PublicReentrantLock(fair);
951          final Condition c = lock.newCondition();
952 <        final CountDownLatch locked = new CountDownLatch(1);
952 >        final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
953          Thread t = newStartedThread(new CheckedInterruptedRunnable() {
954              public void realRun() throws InterruptedException {
955                  lock.lock();
956                  assertLockedByMoi(lock);
957                  assertHasNoWaiters(lock, c);
958 <                locked.countDown();
958 >                pleaseInterrupt.countDown();
959                  try {
960                      await(c, awaitMethod);
961                  } finally {
# Line 940 | Line 966 | public class ReentrantLockTest extends J
966                  }
967              }});
968  
969 <        await(locked);
969 >        await(pleaseInterrupt);
970          assertHasWaiters(lock, c, t);
971          t.interrupt();
972          awaitTermination(t);
# Line 961 | Line 987 | public class ReentrantLockTest extends J
987      public void testSignalAll(boolean fair, final AwaitMethod awaitMethod) {
988          final PublicReentrantLock lock = new PublicReentrantLock(fair);
989          final Condition c = lock.newCondition();
990 <        final CountDownLatch locked = new CountDownLatch(2);
990 >        final CountDownLatch pleaseSignal = new CountDownLatch(2);
991          class Awaiter extends CheckedRunnable {
992              public void realRun() throws InterruptedException {
993                  lock.lock();
994 <                locked.countDown();
994 >                pleaseSignal.countDown();
995                  await(c, awaitMethod);
996                  lock.unlock();
997              }
# Line 974 | Line 1000 | public class ReentrantLockTest extends J
1000          Thread t1 = newStartedThread(new Awaiter());
1001          Thread t2 = newStartedThread(new Awaiter());
1002  
1003 <        await(locked);
1003 >        await(pleaseSignal);
1004          lock.lock();
1005          assertHasWaiters(lock, c, t1, t2);
1006          c.signalAll();
# Line 985 | Line 1011 | public class ReentrantLockTest extends J
1011      }
1012  
1013      /**
1014 <     * signal wakes up waiting threads in FIFO order.
1014 >     * signal wakes up waiting threads in FIFO order
1015       */
1016      public void testSignalWakesFifo()      { testSignalWakesFifo(false); }
1017      public void testSignalWakesFifo_fair() { testSignalWakesFifo(true); }
# Line 1039 | Line 1065 | public class ReentrantLockTest extends J
1065      public void testAwaitLockCount(boolean fair) {
1066          final PublicReentrantLock lock = new PublicReentrantLock(fair);
1067          final Condition c = lock.newCondition();
1068 <        final CountDownLatch locked = new CountDownLatch(2);
1068 >        final CountDownLatch pleaseSignal = new CountDownLatch(2);
1069          Thread t1 = newStartedThread(new CheckedRunnable() {
1070              public void realRun() throws InterruptedException {
1071                  lock.lock();
1072                  assertLockedByMoi(lock);
1073                  assertEquals(1, lock.getHoldCount());
1074 <                locked.countDown();
1074 >                pleaseSignal.countDown();
1075                  c.await();
1076                  assertLockedByMoi(lock);
1077                  assertEquals(1, lock.getHoldCount());
# Line 1058 | Line 1084 | public class ReentrantLockTest extends J
1084                  lock.lock();
1085                  assertLockedByMoi(lock);
1086                  assertEquals(2, lock.getHoldCount());
1087 <                locked.countDown();
1087 >                pleaseSignal.countDown();
1088                  c.await();
1089                  assertLockedByMoi(lock);
1090                  assertEquals(2, lock.getHoldCount());
# Line 1066 | Line 1092 | public class ReentrantLockTest extends J
1092                  lock.unlock();
1093              }});
1094  
1095 <        await(locked);
1095 >        await(pleaseSignal);
1096          lock.lock();
1097          assertHasWaiters(lock, c, t1, t2);
1098          assertEquals(1, lock.getHoldCount());
# Line 1083 | Line 1109 | public class ReentrantLockTest extends J
1109      public void testSerialization()      { testSerialization(false); }
1110      public void testSerialization_fair() { testSerialization(true); }
1111      public void testSerialization(boolean fair) {
1112 <        ReentrantLock lock = new ReentrantLock(fair);
1112 >        final ReentrantLock lock = new ReentrantLock(fair);
1113          lock.lock();
1114  
1115          ReentrantLock clone = serialClone(lock);
# Line 1109 | Line 1135 | public class ReentrantLockTest extends J
1135      public void testToString()      { testToString(false); }
1136      public void testToString_fair() { testToString(true); }
1137      public void testToString(boolean fair) {
1138 <        ReentrantLock lock = new ReentrantLock(fair);
1139 <        String us = lock.toString();
1114 <        assertTrue(us.indexOf("Unlocked") >= 0);
1138 >        final ReentrantLock lock = new ReentrantLock(fair);
1139 >        assertTrue(lock.toString().contains("Unlocked"));
1140          lock.lock();
1141 <        String ls = lock.toString();
1142 <        assertTrue(ls.indexOf("Locked") >= 0);
1141 >        assertTrue(lock.toString().contains("Locked by"));
1142 >        lock.unlock();
1143 >        assertTrue(lock.toString().contains("Unlocked"));
1144 >    }
1145 >
1146 >    /**
1147 >     * Tests scenario for JDK-8187408
1148 >     * AbstractQueuedSynchronizer wait queue corrupted when thread awaits without holding the lock
1149 >     */
1150 >    public void testBug8187408() throws InterruptedException {
1151 >        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
1152 >        final AwaitMethod awaitMethod = randomAwaitMethod();
1153 >        final int nThreads = rnd.nextInt(2, 10);
1154 >        final ReentrantLock lock = new ReentrantLock();
1155 >        final Condition cond = lock.newCondition();
1156 >        final CountDownLatch done = new CountDownLatch(nThreads);
1157 >        final ArrayList<Thread> threads = new ArrayList<>();
1158 >
1159 >        Runnable rogue = () -> {
1160 >            while (done.getCount() > 0) {
1161 >                try {
1162 >                    // call await without holding lock?!
1163 >                    await(cond, awaitMethod);
1164 >                    throw new AssertionError("should throw");
1165 >                }
1166 >                catch (IllegalMonitorStateException success) {}
1167 >                catch (Throwable fail) { threadUnexpectedException(fail); }}};
1168 >        Thread rogueThread = new Thread(rogue, "rogue");
1169 >        threads.add(rogueThread);
1170 >        rogueThread.start();
1171 >
1172 >        Runnable waiter = () -> {
1173 >            lock.lock();
1174 >            try {
1175 >                done.countDown();
1176 >                cond.await();
1177 >            } catch (Throwable fail) {
1178 >                threadUnexpectedException(fail);
1179 >            } finally {
1180 >                lock.unlock();
1181 >            }};
1182 >        for (int i = 0; i < nThreads; i++) {
1183 >            Thread thread = new Thread(waiter, "waiter");
1184 >            threads.add(thread);
1185 >            thread.start();
1186 >        }
1187 >
1188 >        assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS));
1189 >        lock.lock();
1190 >        try {
1191 >            assertEquals(nThreads, lock.getWaitQueueLength(cond));
1192 >        } finally {
1193 >            cond.signalAll();
1194 >            lock.unlock();
1195 >        }
1196 >        for (Thread thread : threads) {
1197 >            thread.join(LONG_DELAY_MS);
1198 >            assertFalse(thread.isAlive());
1199 >        }
1200 >    }
1201 >
1202 >    /**
1203 >     * ThreadMXBean reports the blockers that we expect.
1204 >     */
1205 >    public void testBlockers() {
1206 >        if (!testImplementationDetails) return;
1207 >        final boolean fair = randomBoolean();
1208 >        final boolean timedAcquire = randomBoolean();
1209 >        final boolean timedAwait = randomBoolean();
1210 >        final String syncClassName = fair
1211 >            ? "ReentrantLock$FairSync"
1212 >            : "ReentrantLock$NonfairSync";
1213 >        final String conditionClassName
1214 >            = "AbstractQueuedSynchronizer$ConditionObject";
1215 >        final Thread.State expectedAcquireState = timedAcquire
1216 >            ? Thread.State.TIMED_WAITING
1217 >            : Thread.State.WAITING;
1218 >        final Thread.State expectedAwaitState = timedAwait
1219 >            ? Thread.State.TIMED_WAITING
1220 >            : Thread.State.WAITING;
1221 >        final Lock lock = new ReentrantLock(fair);
1222 >        final Condition condition = lock.newCondition();
1223 >        final AtomicBoolean conditionSatisfied = new AtomicBoolean(false);
1224 >        lock.lock();
1225 >        final Thread thread = newStartedThread((Action) () -> {
1226 >            if (timedAcquire)
1227 >                lock.tryLock(LONGER_DELAY_MS, MILLISECONDS);
1228 >            else
1229 >                lock.lock();
1230 >            while (!conditionSatisfied.get())
1231 >                if (timedAwait)
1232 >                    condition.await(LONGER_DELAY_MS, MILLISECONDS);
1233 >                else
1234 >                    condition.await();
1235 >        });
1236 >        Callable<Boolean> waitingForLock = () -> {
1237 >            String className;
1238 >            return thread.getState() == expectedAcquireState
1239 >            && (className = blockerClassName(thread)) != null
1240 >            && className.endsWith(syncClassName);
1241 >        };
1242 >        waitForThreadToEnterWaitState(thread, waitingForLock);
1243 >
1244 >        lock.unlock();
1245 >        Callable<Boolean> waitingForCondition = () -> {
1246 >            String className;
1247 >            return thread.getState() == expectedAwaitState
1248 >            && (className = blockerClassName(thread)) != null
1249 >            && className.endsWith(conditionClassName);
1250 >        };
1251 >        waitForThreadToEnterWaitState(thread, waitingForCondition);
1252 >
1253 >        // politely release the waiter
1254 >        conditionSatisfied.set(true);
1255 >        lock.lock();
1256 >        try {
1257 >            condition.signal();
1258 >        } finally { lock.unlock(); }
1259 >
1260 >        awaitTermination(thread);
1261      }
1262   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines