| /* | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| /* | |
| * This file is available under and governed by the GNU General Public | |
| * License version 2 only, as published by the Free Software Foundation. | |
| * However, the following notice accompanied the original version of this | |
| * file: | |
| * | |
| * 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/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 junit.framework.Test; | |
| import junit.framework.TestSuite; | |
| public class PhaserTest extends JSR166TestCase { | |
| public static void main(String[] args) { | |
| 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 testConstructorDefaultValues() { | |
| Phaser phaser = new Phaser(); | |
| assertNull(phaser.getParent()); | |
| assertEquals(0, phaser.getRegisteredParties()); | |
| assertEquals(0, phaser.getArrivedParties()); | |
| assertEquals(0, phaser.getUnarrivedParties()); | |
| assertEquals(0, phaser.getPhase()); | |
| } | |
| /** | |
| * Constructing with a negative number of parties throws | |
| * IllegalArgumentException | |
| */ | |
| public void testConstructorNegativeParties() { | |
| try { | |
| new Phaser(-1); | |
| shouldThrow(); | |
| } catch (IllegalArgumentException success) {} | |
| } | |
| /** | |
| * Constructing with a negative number of parties throws | |
| * IllegalArgumentException | |
| */ | |
| public void testConstructorNegativeParties2() { | |
| try { | |
| new Phaser(new Phaser(), -1); | |
| shouldThrow(); | |
| } catch (IllegalArgumentException success) {} | |
| } | |
| /** | |
| * Constructing with a number of parties > 65535 throws | |
| * IllegalArgumentException | |
| */ | |
| public void testConstructorPartiesExceedsLimit() { | |
| new Phaser(maxParties); | |
| try { | |
| new Phaser(maxParties + 1); | |
| shouldThrow(); | |
| } 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()); | |
| } | |
| /** | |
| * The parent being input into the parameter should equal the original | |
| * parent when being returned | |
| */ | |
| public void testConstructor5() { | |
| Phaser parent = new Phaser(); | |
| 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 | |
| */ | |
| public void testRegister1() { | |
| Phaser phaser = new Phaser(); | |
| assertState(phaser, 0, 0, 0); | |
| assertEquals(0, phaser.register()); | |
| assertState(phaser, 0, 1, 1); | |
| } | |
| /** | |
| * Registering more than 65536 parties causes IllegalStateException | |
| */ | |
| public void testRegister2() { | |
| Phaser phaser = new Phaser(0); | |
| 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) {} | |
| 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 | |
| */ | |
| public void testRegister3() { | |
| Phaser phaser = new Phaser(); | |
| assertEquals(0, phaser.register()); | |
| 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 | |
| */ | |
| public void testRegister4() { | |
| Phaser phaser = new Phaser(1); | |
| assertEquals(0, phaser.arrive()); | |
| assertEquals(1, phaser.register()); | |
| assertEquals(1, phaser.arrive()); | |
| assertState(phaser, 1, 2, 1); | |
| } | |
| /** | |
| * 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); | |
| } | |
| /** | |
| * Invoking bulkRegister with a negative parameter throws an | |
| * IllegalArgumentException | |
| */ | |
| public void testBulkRegister1() { | |
| try { | |
| new Phaser().bulkRegister(-1); | |
| shouldThrow(); | |
| } catch (IllegalArgumentException success) {} | |
| } | |
| /** | |
| * bulkRegister should correctly record the number of unarrived | |
| * parties with the number of parties being registered | |
| */ | |
| public void testBulkRegister2() { | |
| Phaser phaser = new Phaser(); | |
| assertEquals(0, phaser.bulkRegister(0)); | |
| assertState(phaser, 0, 0, 0); | |
| assertEquals(0, phaser.bulkRegister(20)); | |
| assertState(phaser, 0, 20, 20); | |
| } | |
| /** | |
| * Registering with a number of parties greater than or equal to 1<<16 | |
| * throws IllegalStateException. | |
| */ | |
| public void testBulkRegister3() { | |
| assertEquals(0, new Phaser().bulkRegister((1 << 16) - 1)); | |
| try { | |
| new Phaser().bulkRegister(1 << 16); | |
| shouldThrow(); | |
| } catch (IllegalStateException success) {} | |
| try { | |
| new Phaser(2).bulkRegister((1 << 16) - 2); | |
| shouldThrow(); | |
| } catch (IllegalStateException success) {} | |
| } | |
| /** | |
| * the phase number increments correctly when tripping the barrier | |
| */ | |
| public void testPhaseIncrement1() { | |
| for (int size = 1; size < 9; size++) { | |
| final Phaser phaser = new Phaser(size); | |
| for (int index = 0; index <= (1 << size); index++) { | |
| int phase = phaser.arrive(); | |
| assertTrue(index % size == 0 ? (index / size) == phase : index - (phase * size) > 0); | |
| } | |
| } | |
| } | |
| /** | |
| * arrive() on a registered phaser increments phase. | |
| */ | |
| public void testArrive1() { | |
| Phaser phaser = new Phaser(1); | |
| assertState(phaser, 0, 1, 1); | |
| assertEquals(0, phaser.arrive()); | |
| assertState(phaser, 1, 1, 1); | |
| } | |
| /** | |
| * arriveAndDeregister does not wait for others to arrive at barrier | |
| */ | |
| public void testArriveAndDeregister() { | |
| final Phaser phaser = new Phaser(1); | |
| 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); | |
| } | |
| /** | |
| * arriveAndDeregister does not wait for others to arrive at barrier | |
| */ | |
| public void testArrive2() { | |
| final Phaser phaser = new Phaser(); | |
| assertEquals(0, phaser.register()); | |
| List<Thread> 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); | |
| } | |
| /** | |
| * arrive() returns a negative number if the Phaser is terminated | |
| */ | |
| 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); | |
| } | |
| /** | |
| * arriveAndDeregister() throws IllegalStateException if number of | |
| * registered or unarrived parties would become negative | |
| */ | |
| public void testArriveAndDeregister1() { | |
| Phaser phaser = new Phaser(); | |
| try { | |
| phaser.arriveAndDeregister(); | |
| shouldThrow(); | |
| } catch (IllegalStateException success) {} | |
| } | |
| /** | |
| * arriveAndDeregister reduces the number of arrived parties | |
| */ | |
| public void testArriveAndDeregister2() { | |
| final Phaser phaser = new Phaser(1); | |
| assertEquals(0, phaser.register()); | |
| assertEquals(0, phaser.arrive()); | |
| assertState(phaser, 0, 2, 1); | |
| assertEquals(0, phaser.arriveAndDeregister()); | |
| assertState(phaser, 1, 1, 1); | |
| } | |
| /** | |
| * 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 testArriveAndDeregister3() { | |
| Phaser parent = new Phaser(); | |
| 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 child is zero after deregistration | |
| */ | |
| public void testArriveAndDeregister4() { | |
| Phaser parent = new Phaser(); | |
| 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); | |
| } | |
| /** | |
| * arriveAndDeregister deregisters one party from its parent when | |
| * the number of parties of root is nonzero after deregistration. | |
| */ | |
| public void testArriveAndDeregister5() { | |
| Phaser root = new Phaser(); | |
| Phaser parent = new Phaser(root); | |
| Phaser child = new Phaser(parent); | |
| 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); | |
| } | |
| /** | |
| * arriveAndDeregister returns the phase in which it leaves the | |
| * phaser in after deregistration | |
| */ | |
| public void testArriveAndDeregister6() { | |
| final Phaser phaser = new Phaser(2); | |
| 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); | |
| } | |
| /** | |
| * awaitAdvance succeeds upon advance | |
| */ | |
| public void testAwaitAdvance1() { | |
| final Phaser phaser = new Phaser(1); | |
| assertEquals(0, phaser.arrive()); | |
| assertEquals(1, phaser.awaitAdvance(0)); | |
| } | |
| /** | |
| * awaitAdvance with a negative parameter will return without affecting the | |
| * phaser | |
| */ | |
| public void testAwaitAdvance2() { | |
| 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, randomTimeout(), randomTimeUnit()); | |
| shouldThrow(); | |
| } catch (InterruptedException success) {} | |
| assertFalse(Thread.interrupted()); | |
| pleaseInterrupt.countDown(); | |
| try { | |
| phaser.awaitAdvanceInterruptibly(0, LONGER_DELAY_MS, MILLISECONDS); | |
| shouldThrow(); | |
| } catch (InterruptedException success) {} | |
| assertFalse(Thread.interrupted()); | |
| }}); | |
| await(pleaseInterrupt); | |
| assertState(phaser, 0, 1, 1); | |
| if (randomBoolean()) assertThreadBlocks(t1, Thread.State.WAITING); | |
| if (randomBoolean()) assertThreadBlocks(t2, Thread.State.TIMED_WAITING); | |
| 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); | |
| assertThreadBlocks(t, Thread.State.WAITING); | |
| 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); | |
| assertThreadBlocks(t, Thread.State.WAITING); | |
| 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 pleaseArrive = new CountDownLatch(1); | |
| Thread t = newStartedThread(new CheckedRunnable() { | |
| public void realRun() { | |
| Thread.currentThread().interrupt(); | |
| assertEquals(0, phaser.register()); | |
| pleaseArrive.countDown(); | |
| assertTrue(Thread.currentThread().isInterrupted()); | |
| assertEquals(1, phaser.arriveAndAwaitAdvance()); | |
| assertTrue(Thread.interrupted()); | |
| }}); | |
| await(pleaseArrive); | |
| assertThreadBlocks(t, Thread.State.WAITING); | |
| 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.interrupted()); | |
| }}); | |
| await(pleaseInterrupt); | |
| assertThreadBlocks(t, Thread.State.WAITING); | |
| 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() { | |
| final Phaser phaser = new Phaser(4); | |
| final AtomicInteger count = new AtomicInteger(0); | |
| List<Thread> 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); | |
| } | |
| /** | |
| * awaitAdvance returns the current phase | |
| */ | |
| public void testAwaitAdvance5() { | |
| final Phaser phaser = new Phaser(1); | |
| assertEquals(1, phaser.awaitAdvance(phaser.arrive())); | |
| assertEquals(1, phaser.getPhase()); | |
| assertEquals(1, phaser.register()); | |
| List<Thread> 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(); | |
| }})); | |
| 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<Phaser> zeroPartyChildren = new ArrayList<>(3); | |
| final List<Phaser> 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<Phaser> 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, MEDIUM_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, MEDIUM_DELAY_MS, MILLISECONDS)); | |
| assertEquals(1, phaser.awaitAdvance(0)); | |
| assertEquals(1, phaser.awaitAdvanceInterruptibly(0)); | |
| assertEquals(1, phaser.awaitAdvanceInterruptibly(0, MEDIUM_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, MEDIUM_DELAY_MS, MILLISECONDS)); | |
| assertEquals(2, phaser.awaitAdvance(0)); | |
| assertEquals(2, phaser.awaitAdvanceInterruptibly(0)); | |
| assertEquals(2, phaser.awaitAdvanceInterruptibly(0, MEDIUM_DELAY_MS, MILLISECONDS)); | |
| assertEquals(2, phaser.awaitAdvance(1)); | |
| assertEquals(2, phaser.awaitAdvanceInterruptibly(1)); | |
| assertEquals(2, phaser.awaitAdvanceInterruptibly(1, MEDIUM_DELAY_MS, MILLISECONDS)); | |
| } | |
| } | |
| /** | |
| * awaitAdvance returns when the phaser is externally terminated | |
| */ | |
| public void testAwaitAdvance6() { | |
| final Phaser phaser = new Phaser(3); | |
| final CountDownLatch pleaseForceTermination = new CountDownLatch(2); | |
| final List<Thread> 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()); | |
| } | |
| /** | |
| * arriveAndAwaitAdvance throws IllegalStateException with no | |
| * unarrived parties | |
| */ | |
| public void testArriveAndAwaitAdvance1() { | |
| Phaser phaser = new Phaser(); | |
| try { | |
| phaser.arriveAndAwaitAdvance(); | |
| shouldThrow(); | |
| } catch (IllegalStateException success) {} | |
| } | |
| /** | |
| * arriveAndAwaitAdvance waits for all threads to arrive, the | |
| * number of arrived parties is the same number that is accounted | |
| * for when the main thread awaitsAdvance | |
| */ | |
| public void testArriveAndAwaitAdvance3() { | |
| final Phaser phaser = new Phaser(1); | |
| final int THREADS = 3; | |
| final CountDownLatch pleaseArrive = new CountDownLatch(THREADS); | |
| final List<Thread> 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) | |
| assertThreadBlocks(thread, Thread.State.WAITING); | |
| 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); | |
| } | |
| } |