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.58 by jsr166, Sat Apr 25 04:55:31 2015 UTC vs.
Revision 1.70 by jsr166, Sun Sep 22 01:59:57 2019 UTC

# Line 8 | Line 8
8  
9   import static java.util.concurrent.TimeUnit.MILLISECONDS;
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  
19 import junit.framework.AssertionFailedError;
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          main(suite(), args);
# Line 85 | 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());
# Line 145 | Line 150 | public class ReentrantLockTest extends J
150  
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 159 | 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)));
# Line 208 | 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 398 | 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();
405                long timeoutMillis = 10;
417                  assertFalse(lock.tryLock(timeoutMillis, MILLISECONDS));
418                  assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
419              }});
# Line 417 | 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 434 | 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 {
438            final ReentrantLock lock = new ReentrantLock(fair);
450              assertFalse(lock.isLocked());
451              lock.lock();
452              assertTrue(lock.isLocked());
# Line 522 | 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 {
526            final ReentrantLock lock = new ReentrantLock(fair);
527            final Condition c = lock.newCondition();
528            lock.lock();
529            long startTime = System.nanoTime();
530            long timeoutMillis = 10;
531            long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis);
543              long nanosRemaining = c.awaitNanos(timeoutNanos);
544              assertTrue(nanosRemaining <= 0);
534            assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
535            lock.unlock();
545          } catch (InterruptedException fail) { threadUnexpectedException(fail); }
546 +        assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
547 +        lock.unlock();
548      }
549  
550      /**
# Line 542 | 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 {
546            final ReentrantLock lock = new ReentrantLock(fair);
547            final Condition c = lock.newCondition();
548            lock.lock();
549            long startTime = System.nanoTime();
550            long timeoutMillis = 10;
562              assertFalse(c.await(timeoutMillis, MILLISECONDS));
552            assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
553            lock.unlock();
563          } catch (InterruptedException fail) { threadUnexpectedException(fail); }
564 +        assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
565 +        lock.unlock();
566      }
567  
568      /**
# Line 560 | 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);
565 <            final Condition c = lock.newCondition();
566 <            lock.lock();
567 <            long startTime = System.nanoTime();
568 <            long timeoutMillis = 10;
569 <            java.util.Date d = new java.util.Date();
570 <            assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + timeoutMillis)));
571 <            assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
572 <            lock.unlock();
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 884 | Line 895 | public class ReentrantLockTest extends J
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();
898 >        final Condition condition = lock.newCondition();
899          final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
900  
901          Thread t1 = newStartedThread(new CheckedRunnable() {
# Line 893 | Line 904 | public class ReentrantLockTest extends J
904                  lock.lock();
905                  pleaseInterrupt.countDown();
906                  Thread.currentThread().interrupt();
907 <                c.awaitUninterruptibly();
907 >                condition.awaitUninterruptibly();
908                  assertTrue(Thread.interrupted());
909                  lock.unlock();
910              }});
# Line 903 | Line 914 | public class ReentrantLockTest extends J
914                  // Interrupt during awaitUninterruptibly
915                  lock.lock();
916                  pleaseInterrupt.countDown();
917 <                c.awaitUninterruptibly();
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 <        t2.interrupt();
927 <
916 <        assertThreadStaysAlive(t1);
917 <        assertTrue(t2.isAlive());
926 >        assertThreadBlocks(t1, Thread.State.WAITING);
927 >        assertThreadBlocks(t2, Thread.State.WAITING);
928  
929          lock.lock();
930 <        c.signalAll();
930 >        condition.signalAll();
931          lock.unlock();
932  
933          awaitTermination(t1);
# Line 1099 | 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 1125 | 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);
1138 >        final ReentrantLock lock = new ReentrantLock(fair);
1139          assertTrue(lock.toString().contains("Unlocked"));
1140          lock.lock();
1141 <        assertTrue(lock.toString().contains("Locked"));
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