summaryrefslogtreecommitdiffstats
path: root/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java')
-rw-r--r--jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java1237
1 files changed, 1237 insertions, 0 deletions
diff --git a/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java b/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
new file mode 100644
index 0000000..ad61a2e
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
@@ -0,0 +1,1237 @@
+/*
+ * 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/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.ForkJoinWorkerThread;
+import java.util.concurrent.RecursiveAction;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import java.util.Arrays;
+import java.util.HashSet;
+
+public class RecursiveActionTest extends JSR166TestCase {
+
+ private static ForkJoinPool mainPool() {
+ return new ForkJoinPool();
+ }
+
+ private static ForkJoinPool singletonPool() {
+ return new ForkJoinPool(1);
+ }
+
+ private static ForkJoinPool asyncSingletonPool() {
+ return new ForkJoinPool(1,
+ ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ null, true);
+ }
+
+ private void testInvokeOnPool(ForkJoinPool pool, RecursiveAction a) {
+ try {
+ checkNotDone(a);
+
+ assertNull(pool.invoke(a));
+
+ checkCompletedNormally(a);
+ } finally {
+ joinPool(pool);
+ }
+ }
+
+ void checkNotDone(RecursiveAction a) {
+ assertFalse(a.isDone());
+ assertFalse(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertFalse(a.isCancelled());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+
+ if (! ForkJoinTask.inForkJoinPool()) {
+ Thread.currentThread().interrupt();
+ try {
+ a.get();
+ shouldThrow();
+ } catch (InterruptedException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ Thread.currentThread().interrupt();
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ try {
+ a.get(0L, SECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCompletedNormally(RecursiveAction a) {
+ assertTrue(a.isDone());
+ assertFalse(a.isCancelled());
+ assertTrue(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+ assertNull(a.join());
+ assertFalse(a.cancel(false));
+ assertFalse(a.cancel(true));
+ try {
+ assertNull(a.get());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ try {
+ assertNull(a.get(5L, SECONDS));
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCancelled(RecursiveAction a) {
+ assertTrue(a.isDone());
+ assertTrue(a.isCancelled());
+ assertFalse(a.isCompletedNormally());
+ assertTrue(a.isCompletedAbnormally());
+ assertTrue(a.getException() instanceof CancellationException);
+ assertNull(a.getRawResult());
+
+ try {
+ a.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCompletedAbnormally(RecursiveAction a, Throwable t) {
+ assertTrue(a.isDone());
+ assertFalse(a.isCancelled());
+ assertFalse(a.isCompletedNormally());
+ assertTrue(a.isCompletedAbnormally());
+ assertSame(t.getClass(), a.getException().getClass());
+ assertNull(a.getRawResult());
+ assertFalse(a.cancel(false));
+ assertFalse(a.cancel(true));
+
+ try {
+ a.join();
+ shouldThrow();
+ } catch (Throwable expected) {
+ assertSame(expected.getClass(), t.getClass());
+ }
+
+ try {
+ a.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t.getClass(), success.getCause().getClass());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t.getClass(), success.getCause().getClass());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ public static final class FJException extends RuntimeException {
+ public FJException() { super(); }
+ public FJException(Throwable cause) { super(cause); }
+ }
+
+ // A simple recursive action for testing
+ final class FibAction extends CheckedRecursiveAction {
+ final int number;
+ int result;
+ FibAction(int n) { number = n; }
+ protected void realCompute() {
+ int n = number;
+ if (n <= 1)
+ result = n;
+ else {
+ FibAction f1 = new FibAction(n - 1);
+ FibAction f2 = new FibAction(n - 2);
+ invokeAll(f1, f2);
+ result = f1.result + f2.result;
+ }
+ }
+ }
+
+ // A recursive action failing in base case
+ static final class FailingFibAction extends RecursiveAction {
+ final int number;
+ int result;
+ FailingFibAction(int n) { number = n; }
+ public void compute() {
+ int n = number;
+ if (n <= 1)
+ throw new FJException();
+ else {
+ FailingFibAction f1 = new FailingFibAction(n - 1);
+ FailingFibAction f2 = new FailingFibAction(n - 2);
+ invokeAll(f1, f2);
+ result = f1.result + f2.result;
+ }
+ }
+ }
+
+ /**
+ * invoke returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks. getRawResult of a RecursiveAction returns null;
+ */
+ public void testInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertNull(f.invoke());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks
+ */
+ public void testQuietlyInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ f.quietlyInvoke();
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task returns when task completes
+ */
+ public void testForkJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertNull(f.join());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join/quietlyJoin of a forked task succeeds in the presence of interrupts
+ */
+ public void testJoinIgnoresInterrupts() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ final Thread myself = Thread.currentThread();
+
+ // test join()
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ assertNull(f.join());
+ Thread.interrupted();
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+
+ f = new FibAction(8);
+ f.cancel(true);
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ Thread.interrupted();
+ checkCancelled(f);
+ }
+
+ f = new FibAction(8);
+ f.completeExceptionally(new FJException());
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ Thread.interrupted();
+ checkCompletedAbnormally(f, success);
+ }
+
+ // test quietlyJoin()
+ f = new FibAction(8);
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ Thread.interrupted();
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+
+ f = new FibAction(8);
+ f.cancel(true);
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ Thread.interrupted();
+ checkCancelled(f);
+
+ f = new FibAction(8);
+ f.completeExceptionally(new FJException());
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ Thread.interrupted();
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ a.reinitialize();
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * join/quietlyJoin of a forked task when not in ForkJoinPool
+ * succeeds in the presence of interrupts
+ */
+ public void testJoinIgnoresInterruptsOutsideForkJoinPool() {
+ final SynchronousQueue<FibAction[]> sq =
+ new SynchronousQueue<FibAction[]>();
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws InterruptedException {
+ FibAction[] fibActions = new FibAction[6];
+ for (int i = 0; i < fibActions.length; i++)
+ fibActions[i] = new FibAction(8);
+
+ fibActions[1].cancel(false);
+ fibActions[2].completeExceptionally(new FJException());
+ fibActions[4].cancel(true);
+ fibActions[5].completeExceptionally(new FJException());
+
+ for (int i = 0; i < fibActions.length; i++)
+ fibActions[i].fork();
+
+ sq.put(fibActions);
+
+ helpQuiesce();
+ }};
+
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ FibAction[] fibActions = sq.take();
+ FibAction f;
+ final Thread myself = Thread.currentThread();
+
+ // test join() ------------
+
+ f = fibActions[0];
+ assertFalse(ForkJoinTask.inForkJoinPool());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ assertNull(f.join());
+ assertTrue(Thread.interrupted());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+
+ f = fibActions[1];
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ assertTrue(Thread.interrupted());
+ checkCancelled(f);
+ }
+
+ f = fibActions[2];
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ assertTrue(Thread.interrupted());
+ checkCompletedAbnormally(f, success);
+ }
+
+ // test quietlyJoin() ---------
+
+ f = fibActions[3];
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ assertTrue(Thread.interrupted());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+
+ f = fibActions[4];
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ assertTrue(Thread.interrupted());
+ checkCancelled(f);
+
+ f = fibActions[5];
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ assertTrue(Thread.interrupted());
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+
+ Thread t;
+
+ t = newStartedThread(r);
+ testInvokeOnPool(mainPool(), a);
+ awaitTermination(t, LONG_DELAY_MS);
+
+ a.reinitialize();
+ t = newStartedThread(r);
+ testInvokeOnPool(singletonPool(), a);
+ awaitTermination(t, LONG_DELAY_MS);
+ }
+
+ /**
+ * get of a forked task returns when task completes
+ */
+ public void testForkGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertNull(f.get());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task returns when task completes
+ */
+ public void testForkTimedGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertNull(f.get(5L, SECONDS));
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get with null time unit throws NPE
+ */
+ public void testForkTimedGetNPE() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(5L, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes
+ */
+ public void testForkQuietlyJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * helpQuiesce returns when tasks are complete.
+ * getQueuedTaskCount returns 0 when quiescent
+ */
+ public void testForkHelpQuiesce() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ helpQuiesce();
+ assertEquals(21, f.result);
+ assertEquals(0, getQueuedTaskCount());
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task completes abnormally
+ */
+ public void testAbnormalInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes abnormally
+ */
+ public void testAbnormalQuietlyInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ f.quietlyInvoke();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingFibAction f = new FailingFibAction(8);
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkTimedGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingFibAction f = new FailingFibAction(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(5L, TimeUnit.SECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes abnormally
+ */
+ public void testAbnormalForkQuietlyJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task cancelled
+ */
+ public void testCancelledInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertTrue(f.cancel(true));
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FibAction f = new FibAction(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkTimedGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FibAction f = new FibAction(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get(5L, SECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task cancelled
+ */
+ public void testCancelledForkQuietlyJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ checkCancelled(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * getPool of executing task returns its pool
+ */
+ public void testGetPool() {
+ final ForkJoinPool mainPool = mainPool();
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertSame(mainPool, getPool());
+ }};
+ testInvokeOnPool(mainPool, a);
+ }
+
+ /**
+ * getPool of non-FJ task returns null
+ */
+ public void testGetPool2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertNull(getPool());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * inForkJoinPool of executing task returns true
+ */
+ public void testInForkJoinPool() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertTrue(inForkJoinPool());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * inForkJoinPool of non-FJ task returns false
+ */
+ public void testInForkJoinPool2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertFalse(inForkJoinPool());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * getPool of current thread in pool returns its pool
+ */
+ public void testWorkerGetPool() {
+ final ForkJoinPool mainPool = mainPool();
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ ForkJoinWorkerThread w =
+ (ForkJoinWorkerThread) Thread.currentThread();
+ assertSame(mainPool, w.getPool());
+ }};
+ testInvokeOnPool(mainPool, a);
+ }
+
+ /**
+ * getPoolIndex of current thread in pool returns 0 <= value < poolSize
+ */
+ public void testWorkerGetPoolIndex() {
+ final ForkJoinPool mainPool = mainPool();
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ ForkJoinWorkerThread w =
+ (ForkJoinWorkerThread) Thread.currentThread();
+ assertTrue(w.getPoolIndex() >= 0);
+ // pool size can shrink after assigning index, so cannot check
+ // assertTrue(w.getPoolIndex() < mainPool.getPoolSize());
+ }};
+ testInvokeOnPool(mainPool, a);
+ }
+
+ /**
+ * setRawResult(null) succeeds
+ */
+ public void testSetRawResult() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ setRawResult(null);
+ assertNull(getRawResult());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * A reinitialized normally completed task may be re-invoked
+ */
+ public void testReinitialize() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ checkNotDone(f);
+
+ for (int i = 0; i < 3; i++) {
+ assertNull(f.invoke());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ f.reinitialize();
+ checkNotDone(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * A reinitialized abnormally completed task may be re-invoked
+ */
+ public void testReinitializeAbnormal() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ checkNotDone(f);
+
+ for (int i = 0; i < 3; i++) {
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ f.reinitialize();
+ checkNotDone(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task throws exception after invoking completeExceptionally
+ */
+ public void testCompleteExceptionally() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ f.completeExceptionally(new FJException());
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task suppresses execution invoking complete
+ */
+ public void testComplete() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ f.complete(null);
+ assertNull(f.invoke());
+ assertEquals(0, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) invokes all task arguments
+ */
+ public void testInvokeAll2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FibAction g = new FibAction(9);
+ invokeAll(f, g);
+ checkCompletedNormally(f);
+ assertEquals(21, f.result);
+ checkCompletedNormally(g);
+ assertEquals(34, g.result);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument invokes task
+ */
+ public void testInvokeAll1() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ invokeAll(f);
+ checkCompletedNormally(f);
+ assertEquals(21, f.result);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument invokes tasks
+ */
+ public void testInvokeAll3() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FibAction g = new FibAction(9);
+ FibAction h = new FibAction(7);
+ invokeAll(f, g, h);
+ assertTrue(f.isDone());
+ assertTrue(g.isDone());
+ assertTrue(h.isDone());
+ checkCompletedNormally(f);
+ assertEquals(21, f.result);
+ checkCompletedNormally(g);
+ assertEquals(34, g.result);
+ checkCompletedNormally(g);
+ assertEquals(13, h.result);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) invokes all tasks in the collection
+ */
+ public void testInvokeAllCollection() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FibAction g = new FibAction(9);
+ FibAction h = new FibAction(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ invokeAll(set);
+ assertTrue(f.isDone());
+ assertTrue(g.isDone());
+ assertTrue(h.isDone());
+ checkCompletedNormally(f);
+ assertEquals(21, f.result);
+ checkCompletedNormally(g);
+ assertEquals(34, g.result);
+ checkCompletedNormally(g);
+ assertEquals(13, h.result);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with any null task throws NPE
+ */
+ public void testInvokeAllNPE() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FibAction g = new FibAction(9);
+ FibAction h = null;
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) throw exception if any task does
+ */
+ public void testAbnormalInvokeAll2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FailingFibAction g = new FailingFibAction(9);
+ try {
+ invokeAll(f, g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument throws exception if task does
+ */
+ public void testAbnormalInvokeAll1() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction g = new FailingFibAction(9);
+ try {
+ invokeAll(g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument throws exception if any task does
+ */
+ public void testAbnormalInvokeAll3() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FailingFibAction g = new FailingFibAction(9);
+ FibAction h = new FibAction(7);
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) throws exception if any task does
+ */
+ public void testAbnormalInvokeAllCollection() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ FibAction g = new FibAction(9);
+ FibAction h = new FibAction(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ try {
+ invokeAll(set);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * tryUnfork returns true for most recent unexecuted task,
+ * and suppresses execution
+ */
+ public void testTryUnfork() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertTrue(f.tryUnfork());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * getSurplusQueuedTaskCount returns > 0 when
+ * there are more tasks than threads
+ */
+ public void testGetSurplusQueuedTaskCount() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction h = new FibAction(7);
+ assertSame(h, h.fork());
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertTrue(getSurplusQueuedTaskCount() > 0);
+ helpQuiesce();
+ assertEquals(0, getSurplusQueuedTaskCount());
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * peekNextLocalTask returns most recent unexecuted task.
+ */
+ public void testPeekNextLocalTask() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(f, peekNextLocalTask());
+ assertNull(f.join());
+ checkCompletedNormally(f);
+ helpQuiesce();
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * pollNextLocalTask returns most recent unexecuted task
+ * without executing it
+ */
+ public void testPollNextLocalTask() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(f, pollNextLocalTask());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * pollTask returns an unexecuted task without executing it
+ */
+ public void testPollTask() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(f, pollTask());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * peekNextLocalTask returns least recent unexecuted task in async mode
+ */
+ public void testPeekNextLocalTaskAsync() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(g, peekNextLocalTask());
+ assertNull(f.join());
+ helpQuiesce();
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ /**
+ * pollNextLocalTask returns least recent unexecuted task without
+ * executing it, in async mode
+ */
+ public void testPollNextLocalTaskAsync() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(g, pollNextLocalTask());
+ helpQuiesce();
+ checkCompletedNormally(f);
+ checkNotDone(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ /**
+ * pollTask returns an unexecuted task without executing it, in
+ * async mode
+ */
+ public void testPollTaskAsync() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(g, pollTask());
+ helpQuiesce();
+ checkCompletedNormally(f);
+ checkNotDone(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ /** Demo from RecursiveAction javadoc */
+ static class SortTask extends RecursiveAction {
+ final long[] array; final int lo, hi;
+ SortTask(long[] array, int lo, int hi) {
+ this.array = array; this.lo = lo; this.hi = hi;
+ }
+ SortTask(long[] array) { this(array, 0, array.length); }
+ protected void compute() {
+ if (hi - lo < THRESHOLD)
+ sortSequentially(lo, hi);
+ else {
+ int mid = (lo + hi) >>> 1;
+ invokeAll(new SortTask(array, lo, mid),
+ new SortTask(array, mid, hi));
+ merge(lo, mid, hi);
+ }
+ }
+ // implementation details follow:
+ static final int THRESHOLD = 100;
+ void sortSequentially(int lo, int hi) {
+ Arrays.sort(array, lo, hi);
+ }
+ void merge(int lo, int mid, int hi) {
+ long[] buf = Arrays.copyOfRange(array, lo, mid);
+ for (int i = 0, j = lo, k = mid; i < buf.length; j++)
+ array[j] = (k == hi || buf[i] < array[k]) ?
+ buf[i++] : array[k++];
+ }
+ }
+
+ /**
+ * SortTask demo works as advertised
+ */
+ public void testSortTaskDemo() {
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ long[] array = new long[1007];
+ for (int i = 0; i < array.length; i++)
+ array[i] = rnd.nextLong();
+ long[] arrayClone = array.clone();
+ testInvokeOnPool(mainPool(), new SortTask(array));
+ Arrays.sort(arrayClone);
+ assertTrue(Arrays.equals(array, arrayClone));
+ }
+}