--- jsr166/src/test/tck/PhaserTest.java 2009/08/03 20:33:57 1.5 +++ jsr166/src/test/tck/PhaserTest.java 2011/06/22 07:46:57 1.33 @@ -1,16 +1,20 @@ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain + * http://creativecommons.org/publicdomain/zero/1.0/ * Other contributors include John Vint */ +import junit.framework.*; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Phaser; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeoutException; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.*; -import junit.framework.Test; -import junit.framework.TestSuite; public class PhaserTest extends JSR166TestCase { @@ -22,48 +26,94 @@ public class PhaserTest extends JSR166Te return new TestSuite(PhaserTest.class); } + private static final int maxParties = 65535; + + /** Checks state of unterminated phaser. */ + protected void assertState(Phaser phaser, + int phase, int parties, int unarrived) { + assertEquals(phase, phaser.getPhase()); + assertEquals(parties, phaser.getRegisteredParties()); + assertEquals(unarrived, phaser.getUnarrivedParties()); + assertEquals(parties - unarrived, phaser.getArrivedParties()); + assertFalse(phaser.isTerminated()); + } + + /** Checks state of terminated phaser. */ + protected void assertTerminated(Phaser phaser, int maxPhase, int parties) { + assertTrue(phaser.isTerminated()); + int expectedPhase = maxPhase + Integer.MIN_VALUE; + assertEquals(expectedPhase, phaser.getPhase()); + assertEquals(parties, phaser.getRegisteredParties()); + assertEquals(expectedPhase, phaser.register()); + assertEquals(expectedPhase, phaser.arrive()); + assertEquals(expectedPhase, phaser.arriveAndDeregister()); + } + + protected void assertTerminated(Phaser phaser, int maxPhase) { + assertTerminated(phaser, maxPhase, 0); + } + /** * Empty constructor builds a new Phaser with no parent, no registered * parties and initial phase number of 0 */ - public void testConstructor1() { + public void testConstructorDefaultValues() { Phaser phaser = new Phaser(); assertNull(phaser.getParent()); + assertEquals(0, phaser.getRegisteredParties()); assertEquals(0, phaser.getArrivedParties()); + assertEquals(0, phaser.getUnarrivedParties()); assertEquals(0, phaser.getPhase()); } /** - * A negative party number for the constructor throws illegal argument - * exception + * Constructing with a negative number of parties throws + * IllegalArgumentException */ - public void testConstructor2() { + public void testConstructorNegativeParties() { try { new Phaser(-1); - this.shouldThrow(); - } catch (IllegalArgumentException success) { - } + shouldThrow(); + } catch (IllegalArgumentException success) {} } /** - * The parent being input into the constructor should equal the original - * parent when being returned + * Constructing with a negative number of parties throws + * IllegalArgumentException */ - public void testConstructor3() { - Phaser parent = new Phaser(); - assertEquals(parent, new Phaser(parent).getParent()); + public void testConstructorNegativeParties2() { + try { + new Phaser(new Phaser(), -1); + shouldThrow(); + } catch (IllegalArgumentException success) {} } /** - * A negative party number for the constructor throws illegal argument - * exception + * Constructing with a number of parties > 65535 throws + * IllegalArgumentException */ - public void testConstructor4() { + public void testConstructorPartiesExceedsLimit() { + new Phaser(maxParties); try { - new Phaser(new Phaser(), -1); + new Phaser(maxParties + 1); shouldThrow(); - } catch (IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} + + new Phaser(new Phaser(), maxParties); + try { + new Phaser(new Phaser(), maxParties + 1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * The parent provided to the constructor should be returned from + * a later call to getParent + */ + public void testConstructor3() { + Phaser parent = new Phaser(); + assertSame(parent, new Phaser(parent).getParent()); + assertNull(new Phaser(null).getParent()); } /** @@ -72,19 +122,19 @@ public class PhaserTest extends JSR166Te */ public void testConstructor5() { Phaser parent = new Phaser(); - assertEquals(parent, new Phaser(parent, 0).getParent()); + assertSame(parent, new Phaser(parent, 0).getParent()); + assertNull(new Phaser(null, 0).getParent()); } /** - * register() will increment the number of unarrived parties by one and not - * affect its arrived parties + * register() will increment the number of unarrived parties by + * one and not affect its arrived parties */ public void testRegister1() { Phaser phaser = new Phaser(); - assertEquals(0, phaser.getUnarrivedParties()); - phaser.register(); - assertEquals(1, phaser.getUnarrivedParties()); - assertEquals(0, phaser.getArrivedParties()); + assertState(phaser, 0, 0, 0); + assertEquals(0, phaser.register()); + assertState(phaser, 0, 1, 1); } /** @@ -92,16 +142,26 @@ public class PhaserTest extends JSR166Te */ public void testRegister2() { Phaser phaser = new Phaser(0); - int expectedUnnarivedParties = (1 << 16) - 1; - for (int i = 0; i < expectedUnnarivedParties; i++) { - phaser.register(); - assertEquals(i + 1, phaser.getUnarrivedParties()); + assertState(phaser, 0, 0, 0); + assertEquals(0, phaser.bulkRegister(maxParties - 10)); + assertState(phaser, 0, maxParties - 10, maxParties - 10); + for (int i = 0; i < 10; i++) { + assertState(phaser, 0, maxParties - 10 + i, maxParties - 10 + i); + assertEquals(0, phaser.register()); } + assertState(phaser, 0, maxParties, maxParties); try { phaser.register(); shouldThrow(); - } catch (IllegalStateException success) { - } + } catch (IllegalStateException success) {} + + try { + phaser.bulkRegister(Integer.MAX_VALUE); + shouldThrow(); + } catch (IllegalStateException success) {} + + assertEquals(0, phaser.bulkRegister(0)); + assertState(phaser, 0, maxParties, maxParties); } /** @@ -111,8 +171,9 @@ public class PhaserTest extends JSR166Te public void testRegister3() { Phaser phaser = new Phaser(); assertEquals(0, phaser.register()); - phaser.arrive(); + assertEquals(0, phaser.arrive()); assertEquals(1, phaser.register()); + assertState(phaser, 1, 2, 2); } /** @@ -121,16 +182,10 @@ public class PhaserTest extends JSR166Te */ public void testRegister4() { Phaser phaser = new Phaser(1); - phaser.arrive(); - int expectedPhase = phaser.register(); - phaser.arrive(); - assertEquals(expectedPhase, phaser.getPhase()); - } - - public void testRegister5() { - Phaser phaser = new Phaser(); - phaser.register(); - assertEquals(1, phaser.getUnarrivedParties()); + assertEquals(0, phaser.arrive()); + assertEquals(1, phaser.register()); + assertEquals(1, phaser.arrive()); + assertState(phaser, 1, 2, 1); } /** @@ -141,8 +196,7 @@ public class PhaserTest extends JSR166Te try { new Phaser().bulkRegister(-1); shouldThrow(); - } catch (IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** @@ -151,8 +205,10 @@ public class PhaserTest extends JSR166Te */ public void testBulkRegister2() { Phaser phaser = new Phaser(); - phaser.bulkRegister(20); - assertEquals(20, phaser.getUnarrivedParties()); + assertEquals(0, phaser.bulkRegister(0)); + assertState(phaser, 0, 0, 0); + assertEquals(0, phaser.bulkRegister(20)); + assertState(phaser, 0, 20, 20); } /** @@ -160,11 +216,17 @@ public class PhaserTest extends JSR166Te * throws IllegalStateException. */ public void testBulkRegister3() { + assertEquals(0, new Phaser().bulkRegister((1 << 16) - 1)); + try { new Phaser().bulkRegister(1 << 16); shouldThrow(); - } catch (IllegalStateException success) { - } + } catch (IllegalStateException success) {} + + try { + new Phaser(2).bulkRegister((1 << 16) - 2); + shouldThrow(); + } catch (IllegalStateException success) {} } /** @@ -181,34 +243,51 @@ public class PhaserTest extends JSR166Te } /** - * Arrive() on a registered phaser increments phase. + * arrive() on a registered phaser increments phase. */ public void testArrive1() { Phaser phaser = new Phaser(1); - phaser.arrive(); - assertEquals(1, phaser.getPhase()); + assertState(phaser, 0, 1, 1); + assertEquals(0, phaser.arrive()); + assertState(phaser, 1, 1, 1); } /** - * arrive does not wait for others to arrive at barrier + * arriveAndDeregister does not wait for others to arrive at barrier */ - public void testArrive2() { + public void testArriveAndDeregister() { final Phaser phaser = new Phaser(1); - phaser.register(); - Thread thread = null; - for (final Runnable r : getRunnables(10, SHORT_DELAY_MS)) { - phaser.register(); - thread = new Thread(new CheckedRunnable() { - void realRun() { - r.run(); - phaser.arriveAndDeregister(); - }}); - thread.start(); + for (int i = 0; i < 10; i++) { + assertState(phaser, 0, 1, 1); + assertEquals(0, phaser.register()); + assertState(phaser, 0, 2, 2); + assertEquals(0, phaser.arriveAndDeregister()); + assertState(phaser, 0, 1, 1); } + assertEquals(0, phaser.arriveAndDeregister()); + assertTerminated(phaser, 1); + } - phaser.arrive(); - assertTrue(thread.isAlive()); - assertFalse(phaser.isTerminated()); + /** + * arriveAndDeregister does not wait for others to arrive at barrier + */ + public void testArrive2() { + final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + List threads = new ArrayList(); + for (int i = 0; i < 10; i++) { + assertEquals(0, phaser.register()); + threads.add(newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.arriveAndDeregister()); + }})); + } + + for (Thread thread : threads) + awaitTermination(thread); + assertState(phaser, 0, 1, 1); + assertEquals(0, phaser.arrive()); + assertState(phaser, 1, 1, 1); } /** @@ -217,8 +296,13 @@ public class PhaserTest extends JSR166Te public void testArrive3() { Phaser phaser = new Phaser(1); phaser.forceTermination(); + assertTerminated(phaser, 0, 1); + assertEquals(0, phaser.getPhase() + Integer.MIN_VALUE); assertTrue(phaser.arrive() < 0); - + assertTrue(phaser.register() < 0); + assertTrue(phaser.arriveAndDeregister() < 0); + assertTrue(phaser.awaitAdvance(1) < 0); + assertTrue(phaser.getPhase() < 0); } /** @@ -230,53 +314,53 @@ public class PhaserTest extends JSR166Te Phaser phaser = new Phaser(); phaser.arriveAndDeregister(); shouldThrow(); - - } catch (IllegalStateException success) { - } + } catch (IllegalStateException success) {} } /** - * arriveAndDeregister deregisters reduces the number of arrived parties + * arriveAndDeregister reduces the number of arrived parties */ - public void testArriveAndDergeister2() { + public void testArriveAndDeregister2() { final Phaser phaser = new Phaser(1); - phaser.register(); - phaser.arrive(); - int p = phaser.getArrivedParties(); - assertTrue(p == 1); - phaser.arriveAndDeregister(); - assertTrue(phaser.getArrivedParties() < p); + assertEquals(0, phaser.register()); + assertEquals(0, phaser.arrive()); + assertState(phaser, 0, 2, 1); + assertEquals(0, phaser.arriveAndDeregister()); + assertState(phaser, 1, 1, 1); } /** - * arriveAndDeregister arrives to the barrier on a phaser with a parent and + * arriveAndDeregister arrives at the barrier on a phaser with a parent and * when a deregistration occurs and causes the phaser to have zero parties * its parent will be deregistered as well */ - public void testArriveAndDeregsiter3() { + public void testArriveAndDeregister3() { Phaser parent = new Phaser(); - Phaser root = new Phaser(parent); - root.register(); - assertTrue(parent.getUnarrivedParties() > 0); - assertTrue(root.getUnarrivedParties() > 0); - root.arriveAndDeregister(); - assertTrue(parent.getUnarrivedParties() == 0); - assertTrue(root.getUnarrivedParties() == 0); - assertTrue(root.isTerminated() && parent.isTerminated()); + Phaser child = new Phaser(parent); + assertState(child, 0, 0, 0); + assertState(parent, 0, 0, 0); + assertEquals(0, child.register()); + assertState(child, 0, 1, 1); + assertState(parent, 0, 1, 1); + assertEquals(0, child.arriveAndDeregister()); + assertTerminated(child, 1); + assertTerminated(parent, 1); } /** * arriveAndDeregister deregisters one party from its parent when - * the number of parties of root is zero after deregistration + * the number of parties of child is zero after deregistration */ - public void testArriveAndDeregsiter4() { + public void testArriveAndDeregister4() { Phaser parent = new Phaser(); - Phaser root = new Phaser(parent); - parent.register(); - root.register(); - int parentParties = parent.getUnarrivedParties(); - root.arriveAndDeregister(); - assertEquals(parentParties - 1, parent.getUnarrivedParties()); + Phaser child = new Phaser(parent); + assertEquals(0, parent.register()); + assertEquals(0, child.register()); + assertState(child, 0, 1, 1); + assertState(parent, 0, 2, 2); + assertEquals(0, child.arriveAndDeregister()); + assertState(child, 0, 0, 0); + assertState(parent, 0, 1, 1); } /** @@ -284,16 +368,20 @@ public class PhaserTest extends JSR166Te * the number of parties of root is nonzero after deregistration. */ public void testArriveAndDeregister5() { - Phaser parent = new Phaser(); + Phaser root = new Phaser(); + Phaser parent = new Phaser(root); Phaser child = new Phaser(parent); - Phaser root = new Phaser(child); - assertTrue(parent.getUnarrivedParties() > 0); - assertTrue(child.getUnarrivedParties() > 0); - root.register(); - root.arriveAndDeregister(); - assertTrue(parent.getUnarrivedParties() == 0); - assertTrue(child.getUnarrivedParties() == 0); - assertTrue(root.isTerminated()); + assertState(root, 0, 0, 0); + assertState(parent, 0, 0, 0); + assertState(child, 0, 0, 0); + assertEquals(0, child.register()); + assertState(root, 0, 1, 1); + assertState(parent, 0, 1, 1); + assertState(child, 0, 1, 1); + assertEquals(0, child.arriveAndDeregister()); + assertTerminated(child, 1); + assertTerminated(parent, 1); + assertTerminated(root, 1); } /** @@ -302,14 +390,17 @@ public class PhaserTest extends JSR166Te */ public void testArriveAndDeregister6() { final Phaser phaser = new Phaser(2); - new Thread(new CheckedRunnable() { - void realRun() { - getRunnable(SHORT_DELAY_MS).run(); - phaser.arrive(); - }}).start(); - phaser.arriveAndAwaitAdvance(); - int phase = phaser.arriveAndDeregister(); - assertEquals(phase, phaser.getPhase()); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.arrive()); + }}); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + assertState(phaser, 1, 2, 2); + assertEquals(1, phaser.arriveAndDeregister()); + assertState(phaser, 1, 1, 1); + assertEquals(1, phaser.arriveAndDeregister()); + assertTerminated(phaser, 2); + awaitTermination(t); } /** @@ -317,7 +408,8 @@ public class PhaserTest extends JSR166Te */ public void testAwaitAdvance1() { final Phaser phaser = new Phaser(1); - phaser.awaitAdvance(phaser.arrive()); + assertEquals(0, phaser.arrive()); + assertEquals(1, phaser.awaitAdvance(0)); } /** @@ -325,61 +417,195 @@ public class PhaserTest extends JSR166Te * phaser */ public void testAwaitAdvance2() { - try { - Phaser phaser = new Phaser(); - phaser.awaitAdvance(-1); - } catch (Exception failure) { - this.unexpectedException(); - } + Phaser phaser = new Phaser(); + assertTrue(phaser.awaitAdvance(-1) < 0); + assertState(phaser, 0, 0, 0); + } + + /** + * awaitAdvanceInterruptibly blocks interruptibly + */ + public void testAwaitAdvanceInterruptibly_interruptible() throws InterruptedException { + final Phaser phaser = new Phaser(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(2); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); + try { + phaser.awaitAdvanceInterruptibly(0); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + phaser.awaitAdvanceInterruptibly(0); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws TimeoutException { + Thread.currentThread().interrupt(); + try { + phaser.awaitAdvanceInterruptibly(0, 2*LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + phaser.awaitAdvanceInterruptibly(0, 2*LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertState(phaser, 0, 1, 1); + assertThreadsStayAlive(t1, t2); + t1.interrupt(); + t2.interrupt(); + awaitTermination(t1); + awaitTermination(t2); + assertState(phaser, 0, 1, 1); + assertEquals(0, phaser.arrive()); + assertState(phaser, 1, 1, 1); } /** - * awaitAdvance while waiting does not abort on interrupt. + * awaitAdvance continues waiting if interrupted before waiting */ - public void testAwaitAdvance3() { + public void testAwaitAdvanceAfterInterrupt() { final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + final CountDownLatch pleaseArrive = new CountDownLatch(1); - Thread th1 = new Thread(new CheckedRunnable() { - void realRun() throws InterruptedException { - phaser.register(); - getRunnable(LONG_DELAY_MS).run(); - phaser.awaitAdvance(phaser.arrive()); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); + assertEquals(0, phaser.register()); + assertEquals(0, phaser.arrive()); + pleaseArrive.countDown(); + assertTrue(Thread.currentThread().isInterrupted()); + assertEquals(1, phaser.awaitAdvance(0)); + assertTrue(Thread.interrupted()); }}); - phaser.register(); - th1.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - th1.interrupt(); - Thread.sleep(LONG_DELAY_MS); - phaser.arrive(); - } catch (InterruptedException failure) { - threadUnexpectedException(failure); - } - assertFalse(th1.isInterrupted()); + + await(pleaseArrive); + waitForThreadToEnterWaitState(t, SHORT_DELAY_MS); + assertEquals(0, phaser.arrive()); + awaitTermination(t); + + Thread.currentThread().interrupt(); + assertEquals(1, phaser.awaitAdvance(0)); + assertTrue(Thread.interrupted()); + } + + /** + * awaitAdvance continues waiting if interrupted while waiting + */ + public void testAwaitAdvanceBeforeInterrupt() { + final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + final CountDownLatch pleaseArrive = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.register()); + assertEquals(0, phaser.arrive()); + assertFalse(Thread.currentThread().isInterrupted()); + pleaseArrive.countDown(); + assertEquals(1, phaser.awaitAdvance(0)); + assertTrue(Thread.interrupted()); + }}); + + await(pleaseArrive); + waitForThreadToEnterWaitState(t, SHORT_DELAY_MS); + t.interrupt(); + assertEquals(0, phaser.arrive()); + awaitTermination(t); + + Thread.currentThread().interrupt(); + assertEquals(1, phaser.awaitAdvance(0)); + assertTrue(Thread.interrupted()); + } + + /** + * arriveAndAwaitAdvance continues waiting if interrupted before waiting + */ + public void testArriveAndAwaitAdvanceAfterInterrupt() { + final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); + assertEquals(0, phaser.register()); + pleaseInterrupt.countDown(); + assertTrue(Thread.currentThread().isInterrupted()); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + assertTrue(Thread.currentThread().isInterrupted()); + }}); + + await(pleaseInterrupt); + waitForThreadToEnterWaitState(t, SHORT_DELAY_MS); + Thread.currentThread().interrupt(); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + assertTrue(Thread.interrupted()); + awaitTermination(t); + } + + /** + * arriveAndAwaitAdvance continues waiting if interrupted while waiting + */ + public void testArriveAndAwaitAdvanceBeforeInterrupt() { + final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.register()); + assertFalse(Thread.currentThread().isInterrupted()); + pleaseInterrupt.countDown(); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + assertTrue(Thread.currentThread().isInterrupted()); + }}); + + await(pleaseInterrupt); + waitForThreadToEnterWaitState(t, SHORT_DELAY_MS); + t.interrupt(); + Thread.currentThread().interrupt(); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + assertTrue(Thread.interrupted()); + awaitTermination(t); } /** * awaitAdvance atomically waits for all parties within the same phase to * complete before continuing */ - public void testAwaitAdvance4() throws InterruptedException { + public void testAwaitAdvance4() { final Phaser phaser = new Phaser(4); - final AtomicInteger phaseCount = new AtomicInteger(0); + final AtomicInteger count = new AtomicInteger(0); List threads = new ArrayList(); - for (int i = 0; i < 4; i++) { - threads.add(new Thread(new CheckedRunnable() { - void realRun() { - int phase = phaser.arrive(); - phaseCount.incrementAndGet(); - getRunnable(LONG_DELAY_MS).run(); - phaser.awaitAdvance(phase); - threadAssertTrue(phaseCount.get() == 4); - }})); - } - for (Thread thread : threads) - thread.start(); + for (int i = 0; i < 4; i++) + threads.add(newStartedThread(new CheckedRunnable() { + public void realRun() { + for (int k = 0; k < 3; k++) { + assertEquals(2*k+1, phaser.arriveAndAwaitAdvance()); + count.incrementAndGet(); + assertEquals(2*k+1, phaser.arrive()); + assertEquals(2*k+2, phaser.awaitAdvance(2*k+1)); + assertEquals(count.get(), 4*(k+1)); + }}})); + for (Thread thread : threads) - thread.join(); + awaitTermination(thread); } /** @@ -387,18 +613,76 @@ public class PhaserTest extends JSR166Te */ public void testAwaitAdvance5() { final Phaser phaser = new Phaser(1); - int phase = phaser.awaitAdvance(phaser.arrive()); - assertEquals(phase, phaser.getPhase()); - phaser.register(); - for (int i = 0; i < eight; i++) { - new Thread(new CheckedRunnable() { - void realRun() { - getRunnable(SHORT_DELAY_MS).run(); + assertEquals(1, phaser.awaitAdvance(phaser.arrive())); + assertEquals(1, phaser.getPhase()); + assertEquals(1, phaser.register()); + List threads = new ArrayList(); + for (int i = 0; i < 8; i++) { + final CountDownLatch latch = new CountDownLatch(1); + final boolean goesFirst = ((i & 1) == 0); + threads.add(newStartedThread(new CheckedRunnable() { + public void realRun() { + if (goesFirst) + latch.countDown(); + else + await(latch); phaser.arrive(); - } - }).start(); - phase = phaser.awaitAdvance(phaser.arrive()); - threadAssertEquals(phase, phaser.getPhase()); + }})); + if (goesFirst) + await(latch); + else + latch.countDown(); + assertEquals(i + 2, phaser.awaitAdvance(phaser.arrive())); + assertEquals(i + 2, phaser.getPhase()); + } + for (Thread thread : threads) + awaitTermination(thread); + } + + /** + * awaitAdvance returns the current phase in child phasers + */ + public void testAwaitAdvanceTieredPhaser() throws Exception { + final Phaser parent = new Phaser(); + final List zeroPartyChildren = new ArrayList(3); + final List onePartyChildren = new ArrayList(3); + for (int i = 0; i < 3; i++) { + zeroPartyChildren.add(new Phaser(parent, 0)); + onePartyChildren.add(new Phaser(parent, 1)); + } + final List phasers = new ArrayList(); + phasers.addAll(zeroPartyChildren); + phasers.addAll(onePartyChildren); + phasers.add(parent); + for (Phaser phaser : phasers) { + assertEquals(-42, phaser.awaitAdvance(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, SMALL_DELAY_MS, MILLISECONDS)); + } + + for (Phaser child : onePartyChildren) + assertEquals(0, child.arrive()); + for (Phaser phaser : phasers) { + assertEquals(-42, phaser.awaitAdvance(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, SMALL_DELAY_MS, MILLISECONDS)); + assertEquals(1, phaser.awaitAdvance(0)); + assertEquals(1, phaser.awaitAdvanceInterruptibly(0)); + assertEquals(1, phaser.awaitAdvanceInterruptibly(0, SMALL_DELAY_MS, MILLISECONDS)); + } + + for (Phaser child : onePartyChildren) + assertEquals(1, child.arrive()); + for (Phaser phaser : phasers) { + assertEquals(-42, phaser.awaitAdvance(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, SMALL_DELAY_MS, MILLISECONDS)); + assertEquals(2, phaser.awaitAdvance(0)); + assertEquals(2, phaser.awaitAdvanceInterruptibly(0)); + assertEquals(2, phaser.awaitAdvanceInterruptibly(0, SMALL_DELAY_MS, MILLISECONDS)); + assertEquals(2, phaser.awaitAdvance(1)); + assertEquals(2, phaser.awaitAdvanceInterruptibly(1)); + assertEquals(2, phaser.awaitAdvanceInterruptibly(1, SMALL_DELAY_MS, MILLISECONDS)); } } @@ -407,38 +691,28 @@ public class PhaserTest extends JSR166Te */ public void testAwaitAdvance6() { final Phaser phaser = new Phaser(3); - /* - * Start new thread. This thread waits a small amount of time - * and waits for the other two parties to arrive. The party - * in the main thread arrives quickly so at best this thread - * waits for the second thread's party to arrive - */ - new Thread(new CheckedRunnable() { - void realRun() { - getRunnable(SMALL_DELAY_MS).run(); - int phase = phaser.awaitAdvance(phaser.arrive()); - /* - * This point is reached when force termination is called in which phase = -1 - */ - threadAssertTrue(phase < 0); - threadAssertTrue(phaser.isTerminated()); - }}).start(); - /* - * This thread will cause the first thread run to wait, in doing so - * the main thread will force termination in which the first thread - * should exit peacefully as this one - */ - new Thread(new CheckedRunnable() { - void realRun() { - getRunnable(LONG_DELAY_MS).run(); - int p1 = phaser.arrive(); - int phase = phaser.awaitAdvance(p1); - threadAssertTrue(phase < 0); - threadAssertTrue(phaser.isTerminated()); - }}).start(); - - phaser.arrive(); + final CountDownLatch pleaseForceTermination = new CountDownLatch(2); + final List threads = new ArrayList(); + for (int i = 0; i < 2; i++) { + Runnable r = new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.arrive()); + pleaseForceTermination.countDown(); + assertTrue(phaser.awaitAdvance(0) < 0); + assertTrue(phaser.isTerminated()); + assertTrue(phaser.getPhase() < 0); + assertEquals(0, phaser.getPhase() + Integer.MIN_VALUE); + assertEquals(3, phaser.getRegisteredParties()); + }}; + threads.add(newStartedThread(r)); + } + await(pleaseForceTermination); phaser.forceTermination(); + assertTrue(phaser.isTerminated()); + assertEquals(0, phaser.getPhase() + Integer.MIN_VALUE); + for (Thread thread : threads) + awaitTermination(thread); + assertEquals(3, phaser.getRegisteredParties()); } /** @@ -450,30 +724,7 @@ public class PhaserTest extends JSR166Te Phaser phaser = new Phaser(); phaser.arriveAndAwaitAdvance(); shouldThrow(); - } catch (IllegalStateException success) { - } - } - - /** - * Interrupted arriveAndAwaitAdvance does not throw InterruptedException - */ - public void testArriveAndAwaitAdvance2() { - final Phaser phaser = new Phaser(2); - Thread th = new Thread(new CheckedRunnable() { - void realRun() { - phaser.arriveAndAwaitAdvance(); - }}); - - try { - th.start(); - Thread.sleep(LONG_DELAY_MS); - th.interrupt(); - Thread.sleep(LONG_DELAY_MS); - phaser.arrive(); - } catch (InterruptedException failure) { - this.unexpectedException(); - } - assertFalse(th.isInterrupted()); + } catch (IllegalStateException success) {} } /** @@ -483,41 +734,32 @@ public class PhaserTest extends JSR166Te */ public void testArriveAndAwaitAdvance3() { final Phaser phaser = new Phaser(1); - final AtomicInteger arrivingCount = new AtomicInteger(0); - for (final Runnable run : getRunnables(six, SHORT_DELAY_MS)) { - new Thread(new CheckedRunnable() { - void realRun() { - phaser.register(); - run.run(); - arrivingCount.getAndIncrement(); - phaser.arrive(); - }}).start(); - } - int phaseNumber = phaser.arriveAndAwaitAdvance(); - arrivingCount.incrementAndGet(); - //the + 1 adds to expectedArrive to account for the main threads arrival - int expectedArrived = phaseNumber > 0 ? phaseNumber * six + 1 : phaser.getArrivedParties() + 1; - threadAssertEquals(expectedArrived, arrivingCount.get()); - } - // .. initially called, for n tasks via - private List getRunnables(int size, long wait) { - List list = new ArrayList(); - for (int i = 0; i < size; i++) { - list.add(getRunnable(wait)); - } - return list; - } + final int THREADS = 3; + final CountDownLatch pleaseArrive = new CountDownLatch(THREADS); + final List threads = new ArrayList(); + for (int i = 0; i < THREADS; i++) + threads.add(newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.register()); + pleaseArrive.countDown(); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + }})); - private Runnable getRunnable(final long wait) { - return new CheckedRunnable() { - void realRun() { - try { - Thread.sleep(wait); - } catch (InterruptedException noop) { - // sleep interruption isn't a problem case for these example - } - } - }; + await(pleaseArrive); + long startTime = System.nanoTime(); + while (phaser.getArrivedParties() < THREADS) + Thread.yield(); + assertEquals(THREADS, phaser.getArrivedParties()); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + for (Thread thread : threads) + waitForThreadToEnterWaitState(thread, SHORT_DELAY_MS); + for (Thread thread : threads) + assertTrue(thread.isAlive()); + assertState(phaser, 0, THREADS + 1, 1); + phaser.arriveAndAwaitAdvance(); + for (Thread thread : threads) + awaitTermination(thread); + assertState(phaser, 1, THREADS + 1, THREADS + 1); } }