1 /* 2 * Written by Doug Lea with assistance from members of JCP JSR-166 3 * Expert Group and released to the public domain, as explained at 4 * http://creativecommons.org/publicdomain/zero/1.0/ 5 * Other contributors include Andrew Wright, Jeffrey Hayes, 6 * Pat Fisher, Mike Judd. 7 */ 8 9 package jsr166; 10 11 import static java.util.concurrent.TimeUnit.MILLISECONDS; 12 13 import java.util.Collection; 14 import java.util.concurrent.CountDownLatch; 15 import java.util.concurrent.Semaphore; 16 17 import junit.framework.AssertionFailedError; 18 import junit.framework.Test; 19 import junit.framework.TestSuite; 20 21 public class SemaphoreTest extends JSR166TestCase { 22 // android-note: Removed because the CTS runner does a bad job of 23 // retrying tests that have suite() declarations. 24 // 25 // public static void main(String[] args) { 26 // main(suite(), args); 27 // } 28 // public static Test suite() { 29 // return new TestSuite(...); 30 // } 31 /** 32 * Subclass to expose protected methods 33 */ 34 static class PublicSemaphore extends Semaphore { 35 PublicSemaphore(int permits) { super(permits); } 36 PublicSemaphore(int permits, boolean fair) { super(permits, fair); } 37 public Collection<Thread> getQueuedThreads() { 38 return super.getQueuedThreads(); 39 } 40 public boolean hasQueuedThread(Thread t) { 41 return super.getQueuedThreads().contains(t); 42 } 43 public void reducePermits(int reduction) { 44 super.reducePermits(reduction); 45 } 46 } 47 48 /** 49 * A runnable calling acquire 50 */ 51 class InterruptibleLockRunnable extends CheckedRunnable { 52 final Semaphore lock; 53 InterruptibleLockRunnable(Semaphore s) { lock = s; } 54 public void realRun() { 55 try { 56 lock.acquire(); 57 } 58 catch (InterruptedException ignored) {} 59 } 60 } 61 62 /** 63 * A runnable calling acquire that expects to be interrupted 64 */ 65 class InterruptedLockRunnable extends CheckedInterruptedRunnable { 66 final Semaphore lock; 67 InterruptedLockRunnable(Semaphore s) { lock = s; } 68 public void realRun() throws InterruptedException { 69 lock.acquire(); 70 } 71 } 72 73 /** 74 * Spin-waits until s.hasQueuedThread(t) becomes true. 75 */ 76 void waitForQueuedThread(PublicSemaphore s, Thread t) { 77 long startTime = System.nanoTime(); 78 while (!s.hasQueuedThread(t)) { 79 if (millisElapsedSince(startTime) > LONG_DELAY_MS) 80 throw new AssertionFailedError("timed out"); 81 Thread.yield(); 82 } 83 assertTrue(s.hasQueuedThreads()); 84 assertTrue(t.isAlive()); 85 } 86 87 /** 88 * Spin-waits until s.hasQueuedThreads() becomes true. 89 */ 90 void waitForQueuedThreads(Semaphore s) { 91 long startTime = System.nanoTime(); 92 while (!s.hasQueuedThreads()) { 93 if (millisElapsedSince(startTime) > LONG_DELAY_MS) 94 throw new AssertionFailedError("timed out"); 95 Thread.yield(); 96 } 97 } 98 99 enum AcquireMethod { 100 acquire() { 101 void acquire(Semaphore s) throws InterruptedException { 102 s.acquire(); 103 } 104 }, 105 acquireN() { 106 void acquire(Semaphore s, int permits) throws InterruptedException { 107 s.acquire(permits); 108 } 109 }, 110 acquireUninterruptibly() { 111 void acquire(Semaphore s) { 112 s.acquireUninterruptibly(); 113 } 114 }, 115 acquireUninterruptiblyN() { 116 void acquire(Semaphore s, int permits) { 117 s.acquireUninterruptibly(permits); 118 } 119 }, 120 tryAcquire() { 121 void acquire(Semaphore s) { 122 assertTrue(s.tryAcquire()); 123 } 124 }, 125 tryAcquireN() { 126 void acquire(Semaphore s, int permits) { 127 assertTrue(s.tryAcquire(permits)); 128 } 129 }, 130 tryAcquireTimed() { 131 void acquire(Semaphore s) throws InterruptedException { 132 assertTrue(s.tryAcquire(2 * LONG_DELAY_MS, MILLISECONDS)); 133 } 134 }, 135 tryAcquireTimedN { 136 void acquire(Semaphore s, int permits) throws InterruptedException { 137 assertTrue(s.tryAcquire(permits, 2 * LONG_DELAY_MS, MILLISECONDS)); 138 } 139 }; 140 141 // Intentionally meta-circular 142 143 /** Acquires 1 permit. */ 144 void acquire(Semaphore s) throws InterruptedException { 145 acquire(s, 1); 146 } 147 /** Acquires the given number of permits. */ 148 void acquire(Semaphore s, int permits) throws InterruptedException { 149 for (int i = 0; i < permits; i++) 150 acquire(s); 151 } 152 } 153 154 /** 155 * Zero, negative, and positive initial values are allowed in constructor 156 */ 157 public void testConstructor() { testConstructor(false); } 158 public void testConstructor_fair() { testConstructor(true); } 159 public void testConstructor(boolean fair) { 160 for (int permits : new int[] { -42, -1, 0, 1, 42 }) { 161 Semaphore s = new Semaphore(permits, fair); 162 assertEquals(permits, s.availablePermits()); 163 assertEquals(fair, s.isFair()); 164 } 165 } 166 167 /** 168 * Constructor without fairness argument behaves as nonfair 169 */ 170 public void testConstructorDefaultsToNonFair() { 171 for (int permits : new int[] { -42, -1, 0, 1, 42 }) { 172 Semaphore s = new Semaphore(permits); 173 assertEquals(permits, s.availablePermits()); 174 assertFalse(s.isFair()); 175 } 176 } 177 178 /** 179 * tryAcquire succeeds when sufficient permits, else fails 180 */ 181 public void testTryAcquireInSameThread() { testTryAcquireInSameThread(false); } 182 public void testTryAcquireInSameThread_fair() { testTryAcquireInSameThread(true); } 183 public void testTryAcquireInSameThread(boolean fair) { 184 Semaphore s = new Semaphore(2, fair); 185 assertEquals(2, s.availablePermits()); 186 assertTrue(s.tryAcquire()); 187 assertTrue(s.tryAcquire()); 188 assertEquals(0, s.availablePermits()); 189 assertFalse(s.tryAcquire()); 190 assertFalse(s.tryAcquire()); 191 assertEquals(0, s.availablePermits()); 192 } 193 194 /** 195 * timed tryAcquire times out 196 */ 197 public void testTryAcquire_timeout() { testTryAcquire_timeout(false); } 198 public void testTryAcquire_timeout_fair() { testTryAcquire_timeout(true); } 199 public void testTryAcquire_timeout(boolean fair) { 200 Semaphore s = new Semaphore(0, fair); 201 long startTime = System.nanoTime(); 202 try { assertFalse(s.tryAcquire(timeoutMillis(), MILLISECONDS)); } 203 catch (InterruptedException e) { threadUnexpectedException(e); } 204 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 205 } 206 207 /** 208 * timed tryAcquire(N) times out 209 */ 210 public void testTryAcquireN_timeout() { testTryAcquireN_timeout(false); } 211 public void testTryAcquireN_timeout_fair() { testTryAcquireN_timeout(true); } 212 public void testTryAcquireN_timeout(boolean fair) { 213 Semaphore s = new Semaphore(2, fair); 214 long startTime = System.nanoTime(); 215 try { assertFalse(s.tryAcquire(3, timeoutMillis(), MILLISECONDS)); } 216 catch (InterruptedException e) { threadUnexpectedException(e); } 217 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 218 } 219 220 /** 221 * acquire(), acquire(N), timed tryAcquired, timed tryAcquire(N) 222 * are interruptible 223 */ 224 public void testInterruptible_acquire() { testInterruptible(false, AcquireMethod.acquire); } 225 public void testInterruptible_acquire_fair() { testInterruptible(true, AcquireMethod.acquire); } 226 public void testInterruptible_acquireN() { testInterruptible(false, AcquireMethod.acquireN); } 227 public void testInterruptible_acquireN_fair() { testInterruptible(true, AcquireMethod.acquireN); } 228 public void testInterruptible_tryAcquireTimed() { testInterruptible(false, AcquireMethod.tryAcquireTimed); } 229 public void testInterruptible_tryAcquireTimed_fair() { testInterruptible(true, AcquireMethod.tryAcquireTimed); } 230 public void testInterruptible_tryAcquireTimedN() { testInterruptible(false, AcquireMethod.tryAcquireTimedN); } 231 public void testInterruptible_tryAcquireTimedN_fair() { testInterruptible(true, AcquireMethod.tryAcquireTimedN); } 232 public void testInterruptible(boolean fair, final AcquireMethod acquirer) { 233 final PublicSemaphore s = new PublicSemaphore(0, fair); 234 final Semaphore pleaseInterrupt = new Semaphore(0, fair); 235 Thread t = newStartedThread(new CheckedRunnable() { 236 public void realRun() { 237 // Interrupt before acquire 238 Thread.currentThread().interrupt(); 239 try { 240 acquirer.acquire(s); 241 shouldThrow(); 242 } catch (InterruptedException success) {} 243 244 // Interrupt during acquire 245 try { 246 acquirer.acquire(s); 247 shouldThrow(); 248 } catch (InterruptedException success) {} 249 250 // Interrupt before acquire(N) 251 Thread.currentThread().interrupt(); 252 try { 253 acquirer.acquire(s, 3); 254 shouldThrow(); 255 } catch (InterruptedException success) {} 256 257 pleaseInterrupt.release(); 258 259 // Interrupt during acquire(N) 260 try { 261 acquirer.acquire(s, 3); 262 shouldThrow(); 263 } catch (InterruptedException success) {} 264 }}); 265 266 waitForQueuedThread(s, t); 267 t.interrupt(); 268 await(pleaseInterrupt); 269 waitForQueuedThread(s, t); 270 t.interrupt(); 271 awaitTermination(t); 272 } 273 274 /** 275 * acquireUninterruptibly(), acquireUninterruptibly(N) are 276 * uninterruptible 277 */ 278 public void testUninterruptible_acquireUninterruptibly() { testUninterruptible(false, AcquireMethod.acquireUninterruptibly); } 279 public void testUninterruptible_acquireUninterruptibly_fair() { testUninterruptible(true, AcquireMethod.acquireUninterruptibly); } 280 public void testUninterruptible_acquireUninterruptiblyN() { testUninterruptible(false, AcquireMethod.acquireUninterruptiblyN); } 281 public void testUninterruptible_acquireUninterruptiblyN_fair() { testUninterruptible(true, AcquireMethod.acquireUninterruptiblyN); } 282 public void testUninterruptible(boolean fair, final AcquireMethod acquirer) { 283 final PublicSemaphore s = new PublicSemaphore(0, fair); 284 final Semaphore pleaseInterrupt = new Semaphore(-1, fair); 285 286 Thread t1 = newStartedThread(new CheckedRunnable() { 287 public void realRun() throws InterruptedException { 288 // Interrupt before acquire 289 pleaseInterrupt.release(); 290 Thread.currentThread().interrupt(); 291 acquirer.acquire(s); 292 assertTrue(Thread.interrupted()); 293 }}); 294 295 Thread t2 = newStartedThread(new CheckedRunnable() { 296 public void realRun() throws InterruptedException { 297 // Interrupt during acquire 298 pleaseInterrupt.release(); 299 acquirer.acquire(s); 300 assertTrue(Thread.interrupted()); 301 }}); 302 303 await(pleaseInterrupt); 304 waitForQueuedThread(s, t1); 305 waitForQueuedThread(s, t2); 306 t2.interrupt(); 307 308 assertThreadStaysAlive(t1); 309 assertTrue(t2.isAlive()); 310 311 s.release(2); 312 313 awaitTermination(t1); 314 awaitTermination(t2); 315 } 316 317 /** 318 * hasQueuedThreads reports whether there are waiting threads 319 */ 320 public void testHasQueuedThreads() { testHasQueuedThreads(false); } 321 public void testHasQueuedThreads_fair() { testHasQueuedThreads(true); } 322 public void testHasQueuedThreads(boolean fair) { 323 final PublicSemaphore lock = new PublicSemaphore(1, fair); 324 assertFalse(lock.hasQueuedThreads()); 325 lock.acquireUninterruptibly(); 326 Thread t1 = newStartedThread(new InterruptedLockRunnable(lock)); 327 waitForQueuedThread(lock, t1); 328 assertTrue(lock.hasQueuedThreads()); 329 Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock)); 330 waitForQueuedThread(lock, t2); 331 assertTrue(lock.hasQueuedThreads()); 332 t1.interrupt(); 333 awaitTermination(t1); 334 assertTrue(lock.hasQueuedThreads()); 335 lock.release(); 336 awaitTermination(t2); 337 assertFalse(lock.hasQueuedThreads()); 338 } 339 340 /** 341 * getQueueLength reports number of waiting threads 342 */ 343 public void testGetQueueLength() { testGetQueueLength(false); } 344 public void testGetQueueLength_fair() { testGetQueueLength(true); } 345 public void testGetQueueLength(boolean fair) { 346 final PublicSemaphore lock = new PublicSemaphore(1, fair); 347 assertEquals(0, lock.getQueueLength()); 348 lock.acquireUninterruptibly(); 349 Thread t1 = newStartedThread(new InterruptedLockRunnable(lock)); 350 waitForQueuedThread(lock, t1); 351 assertEquals(1, lock.getQueueLength()); 352 Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock)); 353 waitForQueuedThread(lock, t2); 354 assertEquals(2, lock.getQueueLength()); 355 t1.interrupt(); 356 awaitTermination(t1); 357 assertEquals(1, lock.getQueueLength()); 358 lock.release(); 359 awaitTermination(t2); 360 assertEquals(0, lock.getQueueLength()); 361 } 362 363 /** 364 * getQueuedThreads includes waiting threads 365 */ 366 public void testGetQueuedThreads() { testGetQueuedThreads(false); } 367 public void testGetQueuedThreads_fair() { testGetQueuedThreads(true); } 368 public void testGetQueuedThreads(boolean fair) { 369 final PublicSemaphore lock = new PublicSemaphore(1, fair); 370 assertTrue(lock.getQueuedThreads().isEmpty()); 371 lock.acquireUninterruptibly(); 372 assertTrue(lock.getQueuedThreads().isEmpty()); 373 Thread t1 = newStartedThread(new InterruptedLockRunnable(lock)); 374 waitForQueuedThread(lock, t1); 375 assertTrue(lock.getQueuedThreads().contains(t1)); 376 Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock)); 377 waitForQueuedThread(lock, t2); 378 assertTrue(lock.getQueuedThreads().contains(t1)); 379 assertTrue(lock.getQueuedThreads().contains(t2)); 380 t1.interrupt(); 381 awaitTermination(t1); 382 assertFalse(lock.getQueuedThreads().contains(t1)); 383 assertTrue(lock.getQueuedThreads().contains(t2)); 384 lock.release(); 385 awaitTermination(t2); 386 assertTrue(lock.getQueuedThreads().isEmpty()); 387 } 388 389 /** 390 * drainPermits reports and removes given number of permits 391 */ 392 public void testDrainPermits() { testDrainPermits(false); } 393 public void testDrainPermits_fair() { testDrainPermits(true); } 394 public void testDrainPermits(boolean fair) { 395 Semaphore s = new Semaphore(0, fair); 396 assertEquals(0, s.availablePermits()); 397 assertEquals(0, s.drainPermits()); 398 s.release(10); 399 assertEquals(10, s.availablePermits()); 400 assertEquals(10, s.drainPermits()); 401 assertEquals(0, s.availablePermits()); 402 assertEquals(0, s.drainPermits()); 403 } 404 405 /** 406 * release(-N) throws IllegalArgumentException 407 */ 408 public void testReleaseIAE() { testReleaseIAE(false); } 409 public void testReleaseIAE_fair() { testReleaseIAE(true); } 410 public void testReleaseIAE(boolean fair) { 411 Semaphore s = new Semaphore(10, fair); 412 try { 413 s.release(-1); 414 shouldThrow(); 415 } catch (IllegalArgumentException success) {} 416 } 417 418 /** 419 * reducePermits(-N) throws IllegalArgumentException 420 */ 421 public void testReducePermitsIAE() { testReducePermitsIAE(false); } 422 public void testReducePermitsIAE_fair() { testReducePermitsIAE(true); } 423 public void testReducePermitsIAE(boolean fair) { 424 PublicSemaphore s = new PublicSemaphore(10, fair); 425 try { 426 s.reducePermits(-1); 427 shouldThrow(); 428 } catch (IllegalArgumentException success) {} 429 } 430 431 /** 432 * reducePermits reduces number of permits 433 */ 434 public void testReducePermits() { testReducePermits(false); } 435 public void testReducePermits_fair() { testReducePermits(true); } 436 public void testReducePermits(boolean fair) { 437 PublicSemaphore s = new PublicSemaphore(10, fair); 438 assertEquals(10, s.availablePermits()); 439 s.reducePermits(0); 440 assertEquals(10, s.availablePermits()); 441 s.reducePermits(1); 442 assertEquals(9, s.availablePermits()); 443 s.reducePermits(10); 444 assertEquals(-1, s.availablePermits()); 445 s.reducePermits(10); 446 assertEquals(-11, s.availablePermits()); 447 s.reducePermits(0); 448 assertEquals(-11, s.availablePermits()); 449 } 450 451 /** 452 * a reserialized semaphore has same number of permits and 453 * fairness, but no queued threads 454 */ 455 public void testSerialization() { testSerialization(false); } 456 public void testSerialization_fair() { testSerialization(true); } 457 public void testSerialization(boolean fair) { 458 try { 459 Semaphore s = new Semaphore(3, fair); 460 s.acquire(); 461 s.acquire(); 462 s.release(); 463 464 Semaphore clone = serialClone(s); 465 assertEquals(fair, s.isFair()); 466 assertEquals(fair, clone.isFair()); 467 assertEquals(2, s.availablePermits()); 468 assertEquals(2, clone.availablePermits()); 469 clone.acquire(); 470 clone.acquire(); 471 clone.release(); 472 assertEquals(2, s.availablePermits()); 473 assertEquals(1, clone.availablePermits()); 474 475 s = new Semaphore(0, fair); 476 Thread t = newStartedThread(new InterruptibleLockRunnable(s)); 477 waitForQueuedThreads(s); 478 clone = serialClone(s); 479 assertEquals(fair, s.isFair()); 480 assertEquals(fair, clone.isFair()); 481 assertEquals(0, s.availablePermits()); 482 assertEquals(0, clone.availablePermits()); 483 assertTrue(s.hasQueuedThreads()); 484 assertFalse(clone.hasQueuedThreads()); 485 s.release(); 486 awaitTermination(t); 487 assertFalse(s.hasQueuedThreads()); 488 assertFalse(clone.hasQueuedThreads()); 489 } catch (InterruptedException e) { threadUnexpectedException(e); } 490 } 491 492 /** 493 * tryAcquire(n) succeeds when sufficient permits, else fails 494 */ 495 public void testTryAcquireNInSameThread() { testTryAcquireNInSameThread(false); } 496 public void testTryAcquireNInSameThread_fair() { testTryAcquireNInSameThread(true); } 497 public void testTryAcquireNInSameThread(boolean fair) { 498 Semaphore s = new Semaphore(2, fair); 499 assertEquals(2, s.availablePermits()); 500 assertFalse(s.tryAcquire(3)); 501 assertEquals(2, s.availablePermits()); 502 assertTrue(s.tryAcquire(2)); 503 assertEquals(0, s.availablePermits()); 504 assertFalse(s.tryAcquire(1)); 505 assertFalse(s.tryAcquire(2)); 506 assertEquals(0, s.availablePermits()); 507 } 508 509 /** 510 * acquire succeeds if permits available 511 */ 512 public void testReleaseAcquireSameThread_acquire() { testReleaseAcquireSameThread(false, AcquireMethod.acquire); } 513 public void testReleaseAcquireSameThread_acquire_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquire); } 514 public void testReleaseAcquireSameThread_acquireN() { testReleaseAcquireSameThread(false, AcquireMethod.acquireN); } 515 public void testReleaseAcquireSameThread_acquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireN); } 516 public void testReleaseAcquireSameThread_acquireUninterruptibly() { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); } 517 public void testReleaseAcquireSameThread_acquireUninterruptibly_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); } 518 public void testReleaseAcquireSameThread_acquireUninterruptiblyN() { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); } 519 public void testReleaseAcquireSameThread_acquireUninterruptiblyN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); } 520 public void testReleaseAcquireSameThread_tryAcquire() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquire); } 521 public void testReleaseAcquireSameThread_tryAcquire_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquire); } 522 public void testReleaseAcquireSameThread_tryAcquireN() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireN); } 523 public void testReleaseAcquireSameThread_tryAcquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireN); } 524 public void testReleaseAcquireSameThread_tryAcquireTimed() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimed); } 525 public void testReleaseAcquireSameThread_tryAcquireTimed_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimed); } 526 public void testReleaseAcquireSameThread_tryAcquireTimedN() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimedN); } 527 public void testReleaseAcquireSameThread_tryAcquireTimedN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimedN); } 528 public void testReleaseAcquireSameThread(boolean fair, 529 final AcquireMethod acquirer) { 530 Semaphore s = new Semaphore(1, fair); 531 for (int i = 1; i < 6; i++) { 532 s.release(i); 533 assertEquals(1 + i, s.availablePermits()); 534 try { 535 acquirer.acquire(s, i); 536 } catch (InterruptedException e) { threadUnexpectedException(e); } 537 assertEquals(1, s.availablePermits()); 538 } 539 } 540 541 /** 542 * release in one thread enables acquire in another thread 543 */ 544 public void testReleaseAcquireDifferentThreads_acquire() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquire); } 545 public void testReleaseAcquireDifferentThreads_acquire_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquire); } 546 public void testReleaseAcquireDifferentThreads_acquireN() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireN); } 547 public void testReleaseAcquireDifferentThreads_acquireN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireN); } 548 public void testReleaseAcquireDifferentThreads_acquireUninterruptibly() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); } 549 public void testReleaseAcquireDifferentThreads_acquireUninterruptibly_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); } 550 public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); } 551 public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); } 552 public void testReleaseAcquireDifferentThreads_tryAcquireTimed() { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimed); } 553 public void testReleaseAcquireDifferentThreads_tryAcquireTimed_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimed); } 554 public void testReleaseAcquireDifferentThreads_tryAcquireTimedN() { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimedN); } 555 public void testReleaseAcquireDifferentThreads_tryAcquireTimedN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimedN); } 556 public void testReleaseAcquireDifferentThreads(boolean fair, 557 final AcquireMethod acquirer) { 558 final Semaphore s = new Semaphore(0, fair); 559 final int rounds = 4; 560 long startTime = System.nanoTime(); 561 Thread t = newStartedThread(new CheckedRunnable() { 562 public void realRun() throws InterruptedException { 563 for (int i = 0; i < rounds; i++) { 564 assertFalse(s.hasQueuedThreads()); 565 if (i % 2 == 0) 566 acquirer.acquire(s); 567 else 568 acquirer.acquire(s, 3); 569 }}}); 570 571 for (int i = 0; i < rounds; i++) { 572 while (! (s.availablePermits() == 0 && s.hasQueuedThreads())) 573 Thread.yield(); 574 assertTrue(t.isAlive()); 575 if (i % 2 == 0) 576 s.release(); 577 else 578 s.release(3); 579 } 580 awaitTermination(t); 581 assertEquals(0, s.availablePermits()); 582 assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); 583 } 584 585 /** 586 * fair locks are strictly FIFO 587 */ 588 public void testFairLocksFifo() { 589 final PublicSemaphore s = new PublicSemaphore(1, true); 590 final CountDownLatch pleaseRelease = new CountDownLatch(1); 591 Thread t1 = newStartedThread(new CheckedRunnable() { 592 public void realRun() throws InterruptedException { 593 // Will block; permits are available, but not three 594 s.acquire(3); 595 }}); 596 597 waitForQueuedThreads(s); 598 599 Thread t2 = newStartedThread(new CheckedRunnable() { 600 public void realRun() throws InterruptedException { 601 // Will fail, even though 1 permit is available 602 assertFalse(s.tryAcquire(0L, MILLISECONDS)); 603 assertFalse(s.tryAcquire(1, 0L, MILLISECONDS)); 604 605 // untimed tryAcquire will barge and succeed 606 assertTrue(s.tryAcquire()); 607 s.release(2); 608 assertTrue(s.tryAcquire(2)); 609 s.release(); 610 611 pleaseRelease.countDown(); 612 // Will queue up behind t1, even though 1 permit is available 613 s.acquire(); 614 }}); 615 616 await(pleaseRelease); 617 waitForQueuedThread(s, t2); 618 s.release(2); 619 awaitTermination(t1); 620 assertTrue(t2.isAlive()); 621 s.release(); 622 awaitTermination(t2); 623 } 624 625 /** 626 * toString indicates current number of permits 627 */ 628 public void testToString() { testToString(false); } 629 public void testToString_fair() { testToString(true); } 630 public void testToString(boolean fair) { 631 PublicSemaphore s = new PublicSemaphore(0, fair); 632 assertTrue(s.toString().contains("Permits = 0")); 633 s.release(); 634 assertTrue(s.toString().contains("Permits = 1")); 635 s.release(2); 636 assertTrue(s.toString().contains("Permits = 3")); 637 s.reducePermits(5); 638 assertTrue(s.toString().contains("Permits = -2")); 639 } 640 641 } 642