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