--- jsr166/src/test/tck/PhaserTest.java 2009/08/01 22:09:13 1.4 +++ jsr166/src/test/tck/PhaserTest.java 2015/05/24 01:42:14 1.42 @@ -1,69 +1,120 @@ /* * 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 static java.util.concurrent.TimeUnit.MILLISECONDS; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Phaser; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.*; + import junit.framework.Test; import junit.framework.TestSuite; public class PhaserTest extends JSR166TestCase { public static void main(String[] args) { - junit.textui.TestRunner.run(suite()); + main(suite(), args); } public static Test suite() { 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 +123,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,47 +143,77 @@ 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 (Exception ex) { - threadUnexpectedException(ex); - } + } catch (IllegalStateException success) {} + + try { + phaser.bulkRegister(Integer.MAX_VALUE); + shouldThrow(); + } catch (IllegalStateException success) {} + + assertEquals(0, phaser.bulkRegister(0)); + assertState(phaser, 0, maxParties, maxParties); } /** - * register() correctly returns the current barrier phase number when - * invoked + * register() correctly returns the current barrier phase number + * when invoked */ 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); } /** - * register causes the next arrive to not increment the phase rather retain - * the phase number + * register causes the next arrive to not increment the phase + * rather retain the phase number */ public void testRegister4() { Phaser phaser = new Phaser(1); - phaser.arrive(); - int expectedPhase = phaser.register(); - phaser.arrive(); - assertEquals(expectedPhase, phaser.getPhase()); + assertEquals(0, phaser.arrive()); + assertEquals(1, phaser.register()); + assertEquals(1, phaser.arrive()); + assertState(phaser, 1, 2, 1); } - public void testRegister5() { - Phaser phaser = new Phaser(); - phaser.register(); - assertEquals(1, phaser.getUnarrivedParties()); + /** + * register on a subphaser that is currently empty succeeds, even + * in the presence of another non-empty subphaser + */ + public void testRegisterEmptySubPhaser() { + Phaser root = new Phaser(); + Phaser child1 = new Phaser(root, 1); + Phaser child2 = new Phaser(root, 0); + assertEquals(0, child2.register()); + assertState(root, 0, 2, 2); + assertState(child1, 0, 1, 1); + assertState(child2, 0, 1, 1); + assertEquals(0, child2.arriveAndDeregister()); + assertState(root, 0, 1, 1); + assertState(child1, 0, 1, 1); + assertState(child2, 0, 0, 0); + assertEquals(0, child2.register()); + assertEquals(0, child2.arriveAndDeregister()); + assertState(root, 0, 1, 1); + assertState(child1, 0, 1, 1); + assertState(child2, 0, 0, 0); + assertEquals(0, child1.arriveAndDeregister()); + assertTerminated(root, 1); + assertTerminated(child1, 1); + assertTerminated(child2, 1); } /** @@ -143,18 +224,19 @@ public class PhaserTest extends JSR166Te try { new Phaser().bulkRegister(-1); shouldThrow(); - } catch (IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** - * bulkRegister should correctly record the number of unarrived parties with - * the number of parties being registered + * bulkRegister should correctly record the number of unarrived + * parties with the number of parties being registered */ 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); } /** @@ -162,11 +244,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) {} } /** @@ -183,36 +271,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() { + 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); + } - public void run() { - r.run(); - phaser.arriveAndDeregister(); - } - }; - thread.start(); + /** + * 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()); + }})); } - phaser.arrive(); - assertTrue(thread.isAlive()); - assertFalse(phaser.isTerminated()); + for (Thread thread : threads) + awaitTermination(thread); + assertState(phaser, 0, 1, 1); + assertEquals(0, phaser.arrive()); + assertState(phaser, 1, 1, 1); } /** @@ -221,8 +324,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,57 +338,57 @@ public class PhaserTest extends JSR166Te * registered or unarrived parties would become negative */ public void testArriveAndDeregister1() { + Phaser phaser = new Phaser(); try { - 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); } /** @@ -288,16 +396,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); } /** @@ -306,16 +418,17 @@ public class PhaserTest extends JSR166Te */ public void testArriveAndDeregister6() { final Phaser phaser = new Phaser(2); - new Thread() { - - public void run() { - 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); } /** @@ -323,7 +436,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)); } /** @@ -331,43 +445,172 @@ 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); } /** - * awaitAdvance while waiting does not abort on interrupt. + * awaitAdvanceInterruptibly blocks interruptibly */ - public void testAwaitAdvance3() { - final Phaser phaser = new Phaser(); - Thread th1 = new Thread() { + public void testAwaitAdvanceInterruptibly_interruptible() throws InterruptedException { + final Phaser phaser = new Phaser(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(2); - public void run() { + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); try { - phaser.register(); - getRunnable(LONG_DELAY_MS).run(); - phaser.awaitAdvance(phaser.arrive()); - } catch (Exception failure) { - threadUnexpectedException(failure); - } + phaser.awaitAdvanceInterruptibly(0); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); - } - }; - phaser.register(); - th1.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - th1.interrupt(); - Thread.sleep(LONG_DELAY_MS); - phaser.arrive(); - } catch (Exception failure) { - unexpectedException(); - } - assertFalse(th1.isInterrupted()); + 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 continues waiting if interrupted before waiting + */ + public void testAwaitAdvanceAfterInterrupt() { + final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + final CountDownLatch pleaseArrive = new CountDownLatch(1); + + 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()); + }}); + + 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); } /** @@ -375,20 +618,22 @@ public class PhaserTest extends JSR166Te * complete before continuing */ public void testAwaitAdvance4() { - final Phaser phaser = new Phaser(four); - final AtomicInteger phaseCount = new AtomicInteger(0); - for (int i = 0; i < four; i++) { - new Thread() { - - public void run() { - int phase = phaser.arrive(); - phaseCount.incrementAndGet(); - getRunnable(LONG_DELAY_MS).run(); - phaser.awaitAdvance(phase); - assertTrue(phaseCount.get() == four); - } - }.start(); - } + final Phaser phaser = new Phaser(4); + final AtomicInteger count = new AtomicInteger(0); + List threads = new ArrayList(); + 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(4 * (k + 1), count.get()); + }}})); + + for (Thread thread : threads) + awaitTermination(thread); } /** @@ -396,19 +641,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() { - - public void run() { - 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()); - assertEquals(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)); } } @@ -417,42 +719,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() { - - public void run() { - 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() { - - public void run() { - 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()); } /** @@ -460,39 +748,11 @@ public class PhaserTest extends JSR166Te * unarrived parties */ public void testArriveAndAwaitAdvance1() { + Phaser phaser = new Phaser(); try { - 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() { - public void run() { - try { - phaser.arriveAndAwaitAdvance(); - } catch (Exception failure) { - threadUnexpectedException(failure); - } - } - }; - - 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) {} } /** @@ -502,47 +762,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() { - - public void run() { - 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; - } - - private Runnable getRunnable(final long wait) { - return new Runnable() { - - public void run() { - try { - Thread.sleep(wait); - } catch (InterruptedException noop) { - // sleep interruption isn't a problem case for these example - } catch (Exception ex) { - threadUnexpectedException(ex); - } - - } - }; + 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()); + }})); + + 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); } }