blob: f303285a4777be90dacd2f3c8b2de5f1b0b68b41 [file] [log] [blame]
Calin Juravle8f0d92b2013-08-01 17:26:00 +01001/*
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
9package jsr166;
10
11import junit.framework.*;
12import java.util.*;
13import java.util.concurrent.CountDownLatch;
14import java.util.concurrent.Semaphore;
15import static java.util.concurrent.TimeUnit.MILLISECONDS;
16
17public 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}