1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  */
  22 
  23 /*
  24  * This file is available under and governed by the GNU General Public
  25  * License version 2 only, as published by the Free Software Foundation.
  26  * However, the following notice accompanied the original version of this
  27  * file:
  28  *
  29  * Written by Doug Lea with assistance from members of JCP JSR-166
  30  * Expert Group and released to the public domain, as explained at
  31  * http://creativecommons.org/publicdomain/zero/1.0/
  32  */
  33 
  34 import static java.util.concurrent.TimeUnit.MILLISECONDS;
  35 
  36 import java.util.Arrays;
  37 import java.util.HashSet;
  38 import java.util.concurrent.CancellationException;
  39 import java.util.concurrent.ExecutionException;
  40 import java.util.concurrent.ForkJoinPool;
  41 import java.util.concurrent.ForkJoinTask;
  42 import java.util.concurrent.ForkJoinWorkerThread;
  43 import java.util.concurrent.RecursiveAction;
  44 import java.util.concurrent.SynchronousQueue;
  45 import java.util.concurrent.ThreadLocalRandom;
  46 import java.util.concurrent.TimeoutException;
  47 
  48 import junit.framework.Test;
  49 import junit.framework.TestSuite;
  50 
  51 public class RecursiveActionTest extends JSR166TestCase {
  52 
  53     public static void main(String[] args) {
  54         main(suite(), args);
  55     }
  56 
  57     public static Test suite() {
  58         return new TestSuite(RecursiveActionTest.class);
  59     }
  60 
  61     private static ForkJoinPool mainPool() {
  62         return new ForkJoinPool();
  63     }
  64 
  65     private static ForkJoinPool singletonPool() {
  66         return new ForkJoinPool(1);
  67     }
  68 
  69     private static ForkJoinPool asyncSingletonPool() {
  70         return new ForkJoinPool(1,
  71                                 ForkJoinPool.defaultForkJoinWorkerThreadFactory,
  72                                 null, true);
  73     }
  74 
  75     private void testInvokeOnPool(ForkJoinPool pool, RecursiveAction a) {
  76         try (PoolCleaner cleaner = cleaner(pool)) {
  77             checkNotDone(a);
  78 
  79             assertNull(pool.invoke(a));
  80 
  81             checkCompletedNormally(a);
  82         }
  83     }
  84 
  85     void checkNotDone(RecursiveAction a) {
  86         assertFalse(a.isDone());
  87         assertFalse(a.isCompletedNormally());
  88         assertFalse(a.isCompletedAbnormally());
  89         assertFalse(a.isCancelled());
  90         assertNull(a.getException());
  91         assertNull(a.getRawResult());
  92 
  93         if (! ForkJoinTask.inForkJoinPool()) {
  94             Thread.currentThread().interrupt();
  95             try {
  96                 a.get();
  97                 shouldThrow();
  98             } catch (InterruptedException success) {
  99             } catch (Throwable fail) { threadUnexpectedException(fail); }
 100 
 101             Thread.currentThread().interrupt();
 102             try {
 103                 a.get(randomTimeout(), randomTimeUnit());
 104                 shouldThrow();
 105             } catch (InterruptedException success) {
 106             } catch (Throwable fail) { threadUnexpectedException(fail); }
 107         }
 108 
 109         try {
 110             a.get(randomExpiredTimeout(), randomTimeUnit());
 111             shouldThrow();
 112         } catch (TimeoutException success) {
 113         } catch (Throwable fail) { threadUnexpectedException(fail); }
 114     }
 115 
 116     void checkCompletedNormally(RecursiveAction a) {
 117         assertTrue(a.isDone());
 118         assertFalse(a.isCancelled());
 119         assertTrue(a.isCompletedNormally());
 120         assertFalse(a.isCompletedAbnormally());
 121         assertNull(a.getException());
 122         assertNull(a.getRawResult());
 123         assertNull(a.join());
 124         assertFalse(a.cancel(false));
 125         assertFalse(a.cancel(true));
 126 
 127         Object v1 = null, v2 = null;
 128         try {
 129             v1 = a.get();
 130             v2 = a.get(randomTimeout(), randomTimeUnit());
 131         } catch (Throwable fail) { threadUnexpectedException(fail); }
 132         assertNull(v1);
 133         assertNull(v2);
 134     }
 135 
 136     void checkCancelled(RecursiveAction a) {
 137         assertTrue(a.isDone());
 138         assertTrue(a.isCancelled());
 139         assertFalse(a.isCompletedNormally());
 140         assertTrue(a.isCompletedAbnormally());
 141         assertTrue(a.getException() instanceof CancellationException);
 142         assertNull(a.getRawResult());
 143 
 144         try {
 145             a.join();
 146             shouldThrow();
 147         } catch (CancellationException success) {
 148         } catch (Throwable fail) { threadUnexpectedException(fail); }
 149 
 150         try {
 151             a.get();
 152             shouldThrow();
 153         } catch (CancellationException success) {
 154         } catch (Throwable fail) { threadUnexpectedException(fail); }
 155 
 156         try {
 157             a.get(randomTimeout(), randomTimeUnit());
 158             shouldThrow();
 159         } catch (CancellationException success) {
 160         } catch (Throwable fail) { threadUnexpectedException(fail); }
 161     }
 162 
 163     void checkCompletedAbnormally(RecursiveAction a, Throwable t) {
 164         assertTrue(a.isDone());
 165         assertFalse(a.isCancelled());
 166         assertFalse(a.isCompletedNormally());
 167         assertTrue(a.isCompletedAbnormally());
 168         assertSame(t.getClass(), a.getException().getClass());
 169         assertNull(a.getRawResult());
 170         assertFalse(a.cancel(false));
 171         assertFalse(a.cancel(true));
 172 
 173         try {
 174             a.join();
 175             shouldThrow();
 176         } catch (Throwable expected) {
 177             assertSame(expected.getClass(), t.getClass());
 178         }
 179 
 180         try {
 181             a.get();
 182             shouldThrow();
 183         } catch (ExecutionException success) {
 184             assertSame(t.getClass(), success.getCause().getClass());
 185         } catch (Throwable fail) { threadUnexpectedException(fail); }
 186 
 187         try {
 188             a.get(randomTimeout(), randomTimeUnit());
 189             shouldThrow();
 190         } catch (ExecutionException success) {
 191             assertSame(t.getClass(), success.getCause().getClass());
 192         } catch (Throwable fail) { threadUnexpectedException(fail); }
 193     }
 194 
 195     public static final class FJException extends RuntimeException {
 196         public FJException() { super(); }
 197         public FJException(Throwable cause) { super(cause); }
 198     }
 199 
 200     /** A simple recursive action for testing. */
 201     final class FibAction extends CheckedRecursiveAction {
 202         final int number;
 203         int result;
 204         FibAction(int n) { number = n; }
 205         protected void realCompute() {
 206             int n = number;
 207             if (n <= 1)
 208                 result = n;
 209             else {
 210                 FibAction f1 = new FibAction(n - 1);
 211                 FibAction f2 = new FibAction(n - 2);
 212                 invokeAll(f1, f2);
 213                 result = f1.result + f2.result;
 214             }
 215         }
 216     }
 217 
 218     /** A recursive action failing in base case. */
 219     static final class FailingFibAction extends RecursiveAction {
 220         final int number;
 221         int result;
 222         FailingFibAction(int n) { number = n; }
 223         public void compute() {
 224             int n = number;
 225             if (n <= 1)
 226                 throw new FJException();
 227             else {
 228                 FailingFibAction f1 = new FailingFibAction(n - 1);
 229                 FailingFibAction f2 = new FailingFibAction(n - 2);
 230                 invokeAll(f1, f2);
 231                 result = f1.result + f2.result;
 232             }
 233         }
 234     }
 235 
 236     /**
 237      * invoke returns when task completes normally.
 238      * isCompletedAbnormally and isCancelled return false for normally
 239      * completed tasks. getRawResult of a RecursiveAction returns null;
 240      */
 241     public void testInvoke() {
 242         RecursiveAction a = new CheckedRecursiveAction() {
 243             protected void realCompute() {
 244                 FibAction f = new FibAction(8);
 245                 assertNull(f.invoke());
 246                 assertEquals(21, f.result);
 247                 checkCompletedNormally(f);
 248             }};
 249         testInvokeOnPool(mainPool(), a);
 250     }
 251 
 252     /**
 253      * quietlyInvoke task returns when task completes normally.
 254      * isCompletedAbnormally and isCancelled return false for normally
 255      * completed tasks
 256      */
 257     public void testQuietlyInvoke() {
 258         RecursiveAction a = new CheckedRecursiveAction() {
 259             protected void realCompute() {
 260                 FibAction f = new FibAction(8);
 261                 f.quietlyInvoke();
 262                 assertEquals(21, f.result);
 263                 checkCompletedNormally(f);
 264             }};
 265         testInvokeOnPool(mainPool(), a);
 266     }
 267 
 268     /**
 269      * join of a forked task returns when task completes
 270      */
 271     public void testForkJoin() {
 272         RecursiveAction a = new CheckedRecursiveAction() {
 273             protected void realCompute() {
 274                 FibAction f = new FibAction(8);
 275                 assertSame(f, f.fork());
 276                 assertNull(f.join());
 277                 assertEquals(21, f.result);
 278                 checkCompletedNormally(f);
 279             }};
 280         testInvokeOnPool(mainPool(), a);
 281     }
 282 
 283     /**
 284      * join/quietlyJoin of a forked task succeeds in the presence of interrupts
 285      */
 286     public void testJoinIgnoresInterrupts() {
 287         RecursiveAction a = new CheckedRecursiveAction() {
 288             protected void realCompute() {
 289                 FibAction f = new FibAction(8);
 290                 final Thread currentThread = Thread.currentThread();
 291 
 292                 // test join()
 293                 assertSame(f, f.fork());
 294                 currentThread.interrupt();
 295                 assertNull(f.join());
 296                 Thread.interrupted();
 297                 assertEquals(21, f.result);
 298                 checkCompletedNormally(f);
 299 
 300                 f = new FibAction(8);
 301                 f.cancel(true);
 302                 assertSame(f, f.fork());
 303                 currentThread.interrupt();
 304                 try {
 305                     f.join();
 306                     shouldThrow();
 307                 } catch (CancellationException success) {
 308                     Thread.interrupted();
 309                     checkCancelled(f);
 310                 }
 311 
 312                 f = new FibAction(8);
 313                 f.completeExceptionally(new FJException());
 314                 assertSame(f, f.fork());
 315                 currentThread.interrupt();
 316                 try {
 317                     f.join();
 318                     shouldThrow();
 319                 } catch (FJException success) {
 320                     Thread.interrupted();
 321                     checkCompletedAbnormally(f, success);
 322                 }
 323 
 324                 // test quietlyJoin()
 325                 f = new FibAction(8);
 326                 assertSame(f, f.fork());
 327                 currentThread.interrupt();
 328                 f.quietlyJoin();
 329                 Thread.interrupted();
 330                 assertEquals(21, f.result);
 331                 checkCompletedNormally(f);
 332 
 333                 f = new FibAction(8);
 334                 f.cancel(true);
 335                 assertSame(f, f.fork());
 336                 currentThread.interrupt();
 337                 f.quietlyJoin();
 338                 Thread.interrupted();
 339                 checkCancelled(f);
 340 
 341                 f = new FibAction(8);
 342                 f.completeExceptionally(new FJException());
 343                 assertSame(f, f.fork());
 344                 currentThread.interrupt();
 345                 f.quietlyJoin();
 346                 Thread.interrupted();
 347                 checkCompletedAbnormally(f, f.getException());
 348             }};
 349         testInvokeOnPool(mainPool(), a);
 350         a.reinitialize();
 351         testInvokeOnPool(singletonPool(), a);
 352     }
 353 
 354     /**
 355      * join/quietlyJoin of a forked task when not in ForkJoinPool
 356      * succeeds in the presence of interrupts
 357      */
 358     public void testJoinIgnoresInterruptsOutsideForkJoinPool() {
 359         final SynchronousQueue<FibAction[]> sq = new SynchronousQueue<>();
 360         RecursiveAction a = new CheckedRecursiveAction() {
 361             protected void realCompute() throws InterruptedException {
 362                 FibAction[] fibActions = new FibAction[6];
 363                 for (int i = 0; i < fibActions.length; i++)
 364                     fibActions[i] = new FibAction(8);
 365 
 366                 fibActions[1].cancel(false);
 367                 fibActions[2].completeExceptionally(new FJException());
 368                 fibActions[4].cancel(true);
 369                 fibActions[5].completeExceptionally(new FJException());
 370 
 371                 for (FibAction fibAction : fibActions)
 372                     fibAction.fork();
 373 
 374                 sq.put(fibActions);
 375 
 376                 helpQuiesce();
 377             }};
 378 
 379         Runnable r = new CheckedRunnable() {
 380             public void realRun() throws InterruptedException {
 381                 FibAction[] fibActions = sq.take();
 382                 FibAction f;
 383                 final Thread currentThread = Thread.currentThread();
 384 
 385                 // test join() ------------
 386 
 387                 f = fibActions[0];
 388                 assertFalse(ForkJoinTask.inForkJoinPool());
 389                 currentThread.interrupt();
 390                 assertNull(f.join());
 391                 assertTrue(Thread.interrupted());
 392                 assertEquals(21, f.result);
 393                 checkCompletedNormally(f);
 394 
 395                 f = fibActions[1];
 396                 currentThread.interrupt();
 397                 try {
 398                     f.join();
 399                     shouldThrow();
 400                 } catch (CancellationException success) {
 401                     assertTrue(Thread.interrupted());
 402                     checkCancelled(f);
 403                 }
 404 
 405                 f = fibActions[2];
 406                 currentThread.interrupt();
 407                 try {
 408                     f.join();
 409                     shouldThrow();
 410                 } catch (FJException success) {
 411                     assertTrue(Thread.interrupted());
 412                     checkCompletedAbnormally(f, success);
 413                 }
 414 
 415                 // test quietlyJoin() ---------
 416 
 417                 f = fibActions[3];
 418                 currentThread.interrupt();
 419                 f.quietlyJoin();
 420                 assertTrue(Thread.interrupted());
 421                 assertEquals(21, f.result);
 422                 checkCompletedNormally(f);
 423 
 424                 f = fibActions[4];
 425                 currentThread.interrupt();
 426                 f.quietlyJoin();
 427                 assertTrue(Thread.interrupted());
 428                 checkCancelled(f);
 429 
 430                 f = fibActions[5];
 431                 currentThread.interrupt();
 432                 f.quietlyJoin();
 433                 assertTrue(Thread.interrupted());
 434                 assertTrue(f.getException() instanceof FJException);
 435                 checkCompletedAbnormally(f, f.getException());
 436             }};
 437 
 438         Thread t;
 439 
 440         t = newStartedThread(r);
 441         testInvokeOnPool(mainPool(), a);
 442         awaitTermination(t);
 443 
 444         a.reinitialize();
 445         t = newStartedThread(r);
 446         testInvokeOnPool(singletonPool(), a);
 447         awaitTermination(t);
 448     }
 449 
 450     /**
 451      * get of a forked task returns when task completes
 452      */
 453     public void testForkGet() {
 454         RecursiveAction a = new CheckedRecursiveAction() {
 455             protected void realCompute() throws Exception {
 456                 FibAction f = new FibAction(8);
 457                 assertSame(f, f.fork());
 458                 assertNull(f.get());
 459                 assertEquals(21, f.result);
 460                 checkCompletedNormally(f);
 461             }};
 462         testInvokeOnPool(mainPool(), a);
 463     }
 464 
 465     /**
 466      * timed get of a forked task returns when task completes
 467      */
 468     public void testForkTimedGet() {
 469         RecursiveAction a = new CheckedRecursiveAction() {
 470             protected void realCompute() throws Exception {
 471                 FibAction f = new FibAction(8);
 472                 assertSame(f, f.fork());
 473                 assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
 474                 assertEquals(21, f.result);
 475                 checkCompletedNormally(f);
 476             }};
 477         testInvokeOnPool(mainPool(), a);
 478     }
 479 
 480     /**
 481      * timed get with null time unit throws NPE
 482      */
 483     public void testForkTimedGetNPE() {
 484         RecursiveAction a = new CheckedRecursiveAction() {
 485             protected void realCompute() throws Exception {
 486                 FibAction f = new FibAction(8);
 487                 assertSame(f, f.fork());
 488                 try {
 489                     f.get(randomTimeout(), null);
 490                     shouldThrow();
 491                 } catch (NullPointerException success) {}
 492             }};
 493         testInvokeOnPool(mainPool(), a);
 494     }
 495 
 496     /**
 497      * quietlyJoin of a forked task returns when task completes
 498      */
 499     public void testForkQuietlyJoin() {
 500         RecursiveAction a = new CheckedRecursiveAction() {
 501             protected void realCompute() {
 502                 FibAction f = new FibAction(8);
 503                 assertSame(f, f.fork());
 504                 f.quietlyJoin();
 505                 assertEquals(21, f.result);
 506                 checkCompletedNormally(f);
 507             }};
 508         testInvokeOnPool(mainPool(), a);
 509     }
 510 
 511     /**
 512      * helpQuiesce returns when tasks are complete.
 513      * getQueuedTaskCount returns 0 when quiescent
 514      */
 515     public void testForkHelpQuiesce() {
 516         RecursiveAction a = new CheckedRecursiveAction() {
 517             protected void realCompute() {
 518                 FibAction f = new FibAction(8);
 519                 assertSame(f, f.fork());
 520                 helpQuiesce();
 521                 while (!f.isDone()) // wait out race
 522                     ;
 523                 assertEquals(21, f.result);
 524                 assertEquals(0, getQueuedTaskCount());
 525                 checkCompletedNormally(f);
 526             }};
 527         testInvokeOnPool(mainPool(), a);
 528     }
 529 
 530     /**
 531      * invoke task throws exception when task completes abnormally
 532      */
 533     public void testAbnormalInvoke() {
 534         RecursiveAction a = new CheckedRecursiveAction() {
 535             protected void realCompute() {
 536                 FailingFibAction f = new FailingFibAction(8);
 537                 try {
 538                     f.invoke();
 539                     shouldThrow();
 540                 } catch (FJException success) {
 541                     checkCompletedAbnormally(f, success);
 542                 }
 543             }};
 544         testInvokeOnPool(mainPool(), a);
 545     }
 546 
 547     /**
 548      * quietlyInvoke task returns when task completes abnormally
 549      */
 550     public void testAbnormalQuietlyInvoke() {
 551         RecursiveAction a = new CheckedRecursiveAction() {
 552             protected void realCompute() {
 553                 FailingFibAction f = new FailingFibAction(8);
 554                 f.quietlyInvoke();
 555                 assertTrue(f.getException() instanceof FJException);
 556                 checkCompletedAbnormally(f, f.getException());
 557             }};
 558         testInvokeOnPool(mainPool(), a);
 559     }
 560 
 561     /**
 562      * join of a forked task throws exception when task completes abnormally
 563      */
 564     public void testAbnormalForkJoin() {
 565         RecursiveAction a = new CheckedRecursiveAction() {
 566             protected void realCompute() {
 567                 FailingFibAction f = new FailingFibAction(8);
 568                 assertSame(f, f.fork());
 569                 try {
 570                     f.join();
 571                     shouldThrow();
 572                 } catch (FJException success) {
 573                     checkCompletedAbnormally(f, success);
 574                 }
 575             }};
 576         testInvokeOnPool(mainPool(), a);
 577     }
 578 
 579     /**
 580      * get of a forked task throws exception when task completes abnormally
 581      */
 582     public void testAbnormalForkGet() {
 583         RecursiveAction a = new CheckedRecursiveAction() {
 584             protected void realCompute() throws Exception {
 585                 FailingFibAction f = new FailingFibAction(8);
 586                 assertSame(f, f.fork());
 587                 try {
 588                     f.get();
 589                     shouldThrow();
 590                 } catch (ExecutionException success) {
 591                     Throwable cause = success.getCause();
 592                     assertTrue(cause instanceof FJException);
 593                     checkCompletedAbnormally(f, cause);
 594                 }
 595             }};
 596         testInvokeOnPool(mainPool(), a);
 597     }
 598 
 599     /**
 600      * timed get of a forked task throws exception when task completes abnormally
 601      */
 602     public void testAbnormalForkTimedGet() {
 603         RecursiveAction a = new CheckedRecursiveAction() {
 604             protected void realCompute() throws Exception {
 605                 FailingFibAction f = new FailingFibAction(8);
 606                 assertSame(f, f.fork());
 607                 try {
 608                     f.get(LONG_DELAY_MS, MILLISECONDS);
 609                     shouldThrow();
 610                 } catch (ExecutionException success) {
 611                     Throwable cause = success.getCause();
 612                     assertTrue(cause instanceof FJException);
 613                     checkCompletedAbnormally(f, cause);
 614                 }
 615             }};
 616         testInvokeOnPool(mainPool(), a);
 617     }
 618 
 619     /**
 620      * quietlyJoin of a forked task returns when task completes abnormally
 621      */
 622     public void testAbnormalForkQuietlyJoin() {
 623         RecursiveAction a = new CheckedRecursiveAction() {
 624             protected void realCompute() {
 625                 FailingFibAction f = new FailingFibAction(8);
 626                 assertSame(f, f.fork());
 627                 f.quietlyJoin();
 628                 assertTrue(f.getException() instanceof FJException);
 629                 checkCompletedAbnormally(f, f.getException());
 630             }};
 631         testInvokeOnPool(mainPool(), a);
 632     }
 633 
 634     /**
 635      * invoke task throws exception when task cancelled
 636      */
 637     public void testCancelledInvoke() {
 638         RecursiveAction a = new CheckedRecursiveAction() {
 639             protected void realCompute() {
 640                 FibAction f = new FibAction(8);
 641                 assertTrue(f.cancel(true));
 642                 try {
 643                     f.invoke();
 644                     shouldThrow();
 645                 } catch (CancellationException success) {
 646                     checkCancelled(f);
 647                 }
 648             }};
 649         testInvokeOnPool(mainPool(), a);
 650     }
 651 
 652     /**
 653      * join of a forked task throws exception when task cancelled
 654      */
 655     public void testCancelledForkJoin() {
 656         RecursiveAction a = new CheckedRecursiveAction() {
 657             protected void realCompute() {
 658                 FibAction f = new FibAction(8);
 659                 assertTrue(f.cancel(true));
 660                 assertSame(f, f.fork());
 661                 try {
 662                     f.join();
 663                     shouldThrow();
 664                 } catch (CancellationException success) {
 665                     checkCancelled(f);
 666                 }
 667             }};
 668         testInvokeOnPool(mainPool(), a);
 669     }
 670 
 671     /**
 672      * get of a forked task throws exception when task cancelled
 673      */
 674     public void testCancelledForkGet() {
 675         RecursiveAction a = new CheckedRecursiveAction() {
 676             protected void realCompute() throws Exception {
 677                 FibAction f = new FibAction(8);
 678                 assertTrue(f.cancel(true));
 679                 assertSame(f, f.fork());
 680                 try {
 681                     f.get();
 682                     shouldThrow();
 683                 } catch (CancellationException success) {
 684                     checkCancelled(f);
 685                 }
 686             }};
 687         testInvokeOnPool(mainPool(), a);
 688     }
 689 
 690     /**
 691      * timed get of a forked task throws exception when task cancelled
 692      */
 693     public void testCancelledForkTimedGet() {
 694         RecursiveAction a = new CheckedRecursiveAction() {
 695             protected void realCompute() throws Exception {
 696                 FibAction f = new FibAction(8);
 697                 assertTrue(f.cancel(true));
 698                 assertSame(f, f.fork());
 699                 try {
 700                     f.get(LONG_DELAY_MS, MILLISECONDS);
 701                     shouldThrow();
 702                 } catch (CancellationException success) {
 703                     checkCancelled(f);
 704                 }
 705             }};
 706         testInvokeOnPool(mainPool(), a);
 707     }
 708 
 709     /**
 710      * quietlyJoin of a forked task returns when task cancelled
 711      */
 712     public void testCancelledForkQuietlyJoin() {
 713         RecursiveAction a = new CheckedRecursiveAction() {
 714             protected void realCompute() {
 715                 FibAction f = new FibAction(8);
 716                 assertTrue(f.cancel(true));
 717                 assertSame(f, f.fork());
 718                 f.quietlyJoin();
 719                 checkCancelled(f);
 720             }};
 721         testInvokeOnPool(mainPool(), a);
 722     }
 723 
 724     /**
 725      * getPool of executing task returns its pool
 726      */
 727     public void testGetPool() {
 728         final ForkJoinPool mainPool = mainPool();
 729         RecursiveAction a = new CheckedRecursiveAction() {
 730             protected void realCompute() {
 731                 assertSame(mainPool, getPool());
 732             }};
 733         testInvokeOnPool(mainPool, a);
 734     }
 735 
 736     /**
 737      * getPool of non-FJ task returns null
 738      */
 739     public void testGetPool2() {
 740         RecursiveAction a = new CheckedRecursiveAction() {
 741             protected void realCompute() {
 742                 assertNull(getPool());
 743             }};
 744         assertNull(a.invoke());
 745     }
 746 
 747     /**
 748      * inForkJoinPool of executing task returns true
 749      */
 750     public void testInForkJoinPool() {
 751         RecursiveAction a = new CheckedRecursiveAction() {
 752             protected void realCompute() {
 753                 assertTrue(inForkJoinPool());
 754             }};
 755         testInvokeOnPool(mainPool(), a);
 756     }
 757 
 758     /**
 759      * inForkJoinPool of non-FJ task returns false
 760      */
 761     public void testInForkJoinPool2() {
 762         RecursiveAction a = new CheckedRecursiveAction() {
 763             protected void realCompute() {
 764                 assertFalse(inForkJoinPool());
 765             }};
 766         assertNull(a.invoke());
 767     }
 768 
 769     /**
 770      * getPool of current thread in pool returns its pool
 771      */
 772     public void testWorkerGetPool() {
 773         final ForkJoinPool mainPool = mainPool();
 774         RecursiveAction a = new CheckedRecursiveAction() {
 775             protected void realCompute() {
 776                 ForkJoinWorkerThread w =
 777                     (ForkJoinWorkerThread) Thread.currentThread();
 778                 assertSame(mainPool, w.getPool());
 779             }};
 780         testInvokeOnPool(mainPool, a);
 781     }
 782 
 783     /**
 784      * getPoolIndex of current thread in pool returns 0 <= value < poolSize
 785      */
 786     public void testWorkerGetPoolIndex() {
 787         final ForkJoinPool mainPool = mainPool();
 788         RecursiveAction a = new CheckedRecursiveAction() {
 789             protected void realCompute() {
 790                 ForkJoinWorkerThread w =
 791                     (ForkJoinWorkerThread) Thread.currentThread();
 792                 assertTrue(w.getPoolIndex() >= 0);
 793                 // pool size can shrink after assigning index, so cannot check
 794                 // assertTrue(w.getPoolIndex() < mainPool.getPoolSize());
 795             }};
 796         testInvokeOnPool(mainPool, a);
 797     }
 798 
 799     /**
 800      * setRawResult(null) succeeds
 801      */
 802     public void testSetRawResult() {
 803         RecursiveAction a = new CheckedRecursiveAction() {
 804             protected void realCompute() {
 805                 setRawResult(null);
 806                 assertNull(getRawResult());
 807             }};
 808         assertNull(a.invoke());
 809     }
 810 
 811     /**
 812      * A reinitialized normally completed task may be re-invoked
 813      */
 814     public void testReinitialize() {
 815         RecursiveAction a = new CheckedRecursiveAction() {
 816             protected void realCompute() {
 817                 FibAction f = new FibAction(8);
 818                 checkNotDone(f);
 819 
 820                 for (int i = 0; i < 3; i++) {
 821                     assertNull(f.invoke());
 822                     assertEquals(21, f.result);
 823                     checkCompletedNormally(f);
 824                     f.reinitialize();
 825                     checkNotDone(f);
 826                 }
 827             }};
 828         testInvokeOnPool(mainPool(), a);
 829     }
 830 
 831     /**
 832      * A reinitialized abnormally completed task may be re-invoked
 833      */
 834     public void testReinitializeAbnormal() {
 835         RecursiveAction a = new CheckedRecursiveAction() {
 836             protected void realCompute() {
 837                 FailingFibAction f = new FailingFibAction(8);
 838                 checkNotDone(f);
 839 
 840                 for (int i = 0; i < 3; i++) {
 841                     try {
 842                         f.invoke();
 843                         shouldThrow();
 844                     } catch (FJException success) {
 845                         checkCompletedAbnormally(f, success);
 846                     }
 847                     f.reinitialize();
 848                     checkNotDone(f);
 849                 }
 850             }};
 851         testInvokeOnPool(mainPool(), a);
 852     }
 853 
 854     /**
 855      * invoke task throws exception after invoking completeExceptionally
 856      */
 857     public void testCompleteExceptionally() {
 858         RecursiveAction a = new CheckedRecursiveAction() {
 859             protected void realCompute() {
 860                 FibAction f = new FibAction(8);
 861                 f.completeExceptionally(new FJException());
 862                 try {
 863                     f.invoke();
 864                     shouldThrow();
 865                 } catch (FJException success) {
 866                     checkCompletedAbnormally(f, success);
 867                 }
 868             }};
 869         testInvokeOnPool(mainPool(), a);
 870     }
 871 
 872     /**
 873      * invoke task suppresses execution invoking complete
 874      */
 875     public void testComplete() {
 876         RecursiveAction a = new CheckedRecursiveAction() {
 877             protected void realCompute() {
 878                 FibAction f = new FibAction(8);
 879                 f.complete(null);
 880                 assertNull(f.invoke());
 881                 assertEquals(0, f.result);
 882                 checkCompletedNormally(f);
 883             }};
 884         testInvokeOnPool(mainPool(), a);
 885     }
 886 
 887     /**
 888      * invokeAll(t1, t2) invokes all task arguments
 889      */
 890     public void testInvokeAll2() {
 891         RecursiveAction a = new CheckedRecursiveAction() {
 892             protected void realCompute() {
 893                 FibAction f = new FibAction(8);
 894                 FibAction g = new FibAction(9);
 895                 invokeAll(f, g);
 896                 checkCompletedNormally(f);
 897                 assertEquals(21, f.result);
 898                 checkCompletedNormally(g);
 899                 assertEquals(34, g.result);
 900             }};
 901         testInvokeOnPool(mainPool(), a);
 902     }
 903 
 904     /**
 905      * invokeAll(tasks) with 1 argument invokes task
 906      */
 907     public void testInvokeAll1() {
 908         RecursiveAction a = new CheckedRecursiveAction() {
 909             protected void realCompute() {
 910                 FibAction f = new FibAction(8);
 911                 invokeAll(f);
 912                 checkCompletedNormally(f);
 913                 assertEquals(21, f.result);
 914             }};
 915         testInvokeOnPool(mainPool(), a);
 916     }
 917 
 918     /**
 919      * invokeAll(tasks) with > 2 argument invokes tasks
 920      */
 921     public void testInvokeAll3() {
 922         RecursiveAction a = new CheckedRecursiveAction() {
 923             protected void realCompute() {
 924                 FibAction f = new FibAction(8);
 925                 FibAction g = new FibAction(9);
 926                 FibAction h = new FibAction(7);
 927                 invokeAll(f, g, h);
 928                 assertTrue(f.isDone());
 929                 assertTrue(g.isDone());
 930                 assertTrue(h.isDone());
 931                 checkCompletedNormally(f);
 932                 assertEquals(21, f.result);
 933                 checkCompletedNormally(g);
 934                 assertEquals(34, g.result);
 935                 checkCompletedNormally(g);
 936                 assertEquals(13, h.result);
 937             }};
 938         testInvokeOnPool(mainPool(), a);
 939     }
 940 
 941     /**
 942      * invokeAll(collection) invokes all tasks in the collection
 943      */
 944     public void testInvokeAllCollection() {
 945         RecursiveAction a = new CheckedRecursiveAction() {
 946             protected void realCompute() {
 947                 FibAction f = new FibAction(8);
 948                 FibAction g = new FibAction(9);
 949                 FibAction h = new FibAction(7);
 950                 HashSet set = new HashSet();
 951                 set.add(f);
 952                 set.add(g);
 953                 set.add(h);
 954                 invokeAll(set);
 955                 assertTrue(f.isDone());
 956                 assertTrue(g.isDone());
 957                 assertTrue(h.isDone());
 958                 checkCompletedNormally(f);
 959                 assertEquals(21, f.result);
 960                 checkCompletedNormally(g);
 961                 assertEquals(34, g.result);
 962                 checkCompletedNormally(g);
 963                 assertEquals(13, h.result);
 964             }};
 965         testInvokeOnPool(mainPool(), a);
 966     }
 967 
 968     /**
 969      * invokeAll(tasks) with any null task throws NPE
 970      */
 971     public void testInvokeAllNPE() {
 972         RecursiveAction a = new CheckedRecursiveAction() {
 973             protected void realCompute() {
 974                 FibAction f = new FibAction(8);
 975                 FibAction g = new FibAction(9);
 976                 FibAction h = null;
 977                 try {
 978                     invokeAll(f, g, h);
 979                     shouldThrow();
 980                 } catch (NullPointerException success) {}
 981             }};
 982         testInvokeOnPool(mainPool(), a);
 983     }
 984 
 985     /**
 986      * invokeAll(t1, t2) throw exception if any task does
 987      */
 988     public void testAbnormalInvokeAll2() {
 989         RecursiveAction a = new CheckedRecursiveAction() {
 990             protected void realCompute() {
 991                 FibAction f = new FibAction(8);
 992                 FailingFibAction g = new FailingFibAction(9);
 993                 try {
 994                     invokeAll(f, g);
 995                     shouldThrow();
 996                 } catch (FJException success) {
 997                     checkCompletedAbnormally(g, success);
 998                 }
 999             }};
1000         testInvokeOnPool(mainPool(), a);
1001     }
1002 
1003     /**
1004      * invokeAll(tasks) with 1 argument throws exception if task does
1005      */
1006     public void testAbnormalInvokeAll1() {
1007         RecursiveAction a = new CheckedRecursiveAction() {
1008             protected void realCompute() {
1009                 FailingFibAction g = new FailingFibAction(9);
1010                 try {
1011                     invokeAll(g);
1012                     shouldThrow();
1013                 } catch (FJException success) {
1014                     checkCompletedAbnormally(g, success);
1015                 }
1016             }};
1017         testInvokeOnPool(mainPool(), a);
1018     }
1019 
1020     /**
1021      * invokeAll(tasks) with > 2 argument throws exception if any task does
1022      */
1023     public void testAbnormalInvokeAll3() {
1024         RecursiveAction a = new CheckedRecursiveAction() {
1025             protected void realCompute() {
1026                 FibAction f = new FibAction(8);
1027                 FailingFibAction g = new FailingFibAction(9);
1028                 FibAction h = new FibAction(7);
1029                 try {
1030                     invokeAll(f, g, h);
1031                     shouldThrow();
1032                 } catch (FJException success) {
1033                     checkCompletedAbnormally(g, success);
1034                 }
1035             }};
1036         testInvokeOnPool(mainPool(), a);
1037     }
1038 
1039     /**
1040      * invokeAll(collection) throws exception if any task does
1041      */
1042     public void testAbnormalInvokeAllCollection() {
1043         RecursiveAction a = new CheckedRecursiveAction() {
1044             protected void realCompute() {
1045                 FailingFibAction f = new FailingFibAction(8);
1046                 FibAction g = new FibAction(9);
1047                 FibAction h = new FibAction(7);
1048                 HashSet set = new HashSet();
1049                 set.add(f);
1050                 set.add(g);
1051                 set.add(h);
1052                 try {
1053                     invokeAll(set);
1054                     shouldThrow();
1055                 } catch (FJException success) {
1056                     checkCompletedAbnormally(f, success);
1057                 }
1058             }};
1059         testInvokeOnPool(mainPool(), a);
1060     }
1061 
1062     /**
1063      * tryUnfork returns true for most recent unexecuted task,
1064      * and suppresses execution
1065      */
1066     public void testTryUnfork() {
1067         RecursiveAction a = new CheckedRecursiveAction() {
1068             protected void realCompute() {
1069                 FibAction g = new FibAction(9);
1070                 assertSame(g, g.fork());
1071                 FibAction f = new FibAction(8);
1072                 assertSame(f, f.fork());
1073                 assertTrue(f.tryUnfork());
1074                 helpQuiesce();
1075                 checkNotDone(f);
1076                 checkCompletedNormally(g);
1077             }};
1078         testInvokeOnPool(singletonPool(), a);
1079     }
1080 
1081     /**
1082      * getSurplusQueuedTaskCount returns > 0 when
1083      * there are more tasks than threads
1084      */
1085     public void testGetSurplusQueuedTaskCount() {
1086         RecursiveAction a = new CheckedRecursiveAction() {
1087             protected void realCompute() {
1088                 FibAction h = new FibAction(7);
1089                 assertSame(h, h.fork());
1090                 FibAction g = new FibAction(9);
1091                 assertSame(g, g.fork());
1092                 FibAction f = new FibAction(8);
1093                 assertSame(f, f.fork());
1094                 assertTrue(getSurplusQueuedTaskCount() > 0);
1095                 helpQuiesce();
1096                 assertEquals(0, getSurplusQueuedTaskCount());
1097                 checkCompletedNormally(f);
1098                 checkCompletedNormally(g);
1099                 checkCompletedNormally(h);
1100             }};
1101         testInvokeOnPool(singletonPool(), a);
1102     }
1103 
1104     /**
1105      * peekNextLocalTask returns most recent unexecuted task.
1106      */
1107     public void testPeekNextLocalTask() {
1108         RecursiveAction a = new CheckedRecursiveAction() {
1109             protected void realCompute() {
1110                 FibAction g = new FibAction(9);
1111                 assertSame(g, g.fork());
1112                 FibAction f = new FibAction(8);
1113                 assertSame(f, f.fork());
1114                 assertSame(f, peekNextLocalTask());
1115                 assertNull(f.join());
1116                 checkCompletedNormally(f);
1117                 helpQuiesce();
1118                 checkCompletedNormally(f);
1119                 checkCompletedNormally(g);
1120             }};
1121         testInvokeOnPool(singletonPool(), a);
1122     }
1123 
1124     /**
1125      * pollNextLocalTask returns most recent unexecuted task
1126      * without executing it
1127      */
1128     public void testPollNextLocalTask() {
1129         RecursiveAction a = new CheckedRecursiveAction() {
1130             protected void realCompute() {
1131                 FibAction g = new FibAction(9);
1132                 assertSame(g, g.fork());
1133                 FibAction f = new FibAction(8);
1134                 assertSame(f, f.fork());
1135                 assertSame(f, pollNextLocalTask());
1136                 helpQuiesce();
1137                 checkNotDone(f);
1138                 checkCompletedNormally(g);
1139             }};
1140         testInvokeOnPool(singletonPool(), a);
1141     }
1142 
1143     /**
1144      * pollTask returns an unexecuted task without executing it
1145      */
1146     public void testPollTask() {
1147         RecursiveAction a = new CheckedRecursiveAction() {
1148             protected void realCompute() {
1149                 FibAction g = new FibAction(9);
1150                 assertSame(g, g.fork());
1151                 FibAction f = new FibAction(8);
1152                 assertSame(f, f.fork());
1153                 assertSame(f, pollTask());
1154                 helpQuiesce();
1155                 checkNotDone(f);
1156                 checkCompletedNormally(g);
1157             }};
1158         testInvokeOnPool(singletonPool(), a);
1159     }
1160 
1161     /**
1162      * peekNextLocalTask returns least recent unexecuted task in async mode
1163      */
1164     public void testPeekNextLocalTaskAsync() {
1165         RecursiveAction a = new CheckedRecursiveAction() {
1166             protected void realCompute() {
1167                 FibAction g = new FibAction(9);
1168                 assertSame(g, g.fork());
1169                 FibAction f = new FibAction(8);
1170                 assertSame(f, f.fork());
1171                 assertSame(g, peekNextLocalTask());
1172                 assertNull(f.join());
1173                 helpQuiesce();
1174                 checkCompletedNormally(f);
1175                 checkCompletedNormally(g);
1176             }};
1177         testInvokeOnPool(asyncSingletonPool(), a);
1178     }
1179 
1180     /**
1181      * pollNextLocalTask returns least recent unexecuted task without
1182      * executing it, in async mode
1183      */
1184     public void testPollNextLocalTaskAsync() {
1185         RecursiveAction a = new CheckedRecursiveAction() {
1186             protected void realCompute() {
1187                 FibAction g = new FibAction(9);
1188                 assertSame(g, g.fork());
1189                 FibAction f = new FibAction(8);
1190                 assertSame(f, f.fork());
1191                 assertSame(g, pollNextLocalTask());
1192                 helpQuiesce();
1193                 checkCompletedNormally(f);
1194                 checkNotDone(g);
1195             }};
1196         testInvokeOnPool(asyncSingletonPool(), a);
1197     }
1198 
1199     /**
1200      * pollTask returns an unexecuted task without executing it, in
1201      * async mode
1202      */
1203     public void testPollTaskAsync() {
1204         RecursiveAction a = new CheckedRecursiveAction() {
1205             protected void realCompute() {
1206                 FibAction g = new FibAction(9);
1207                 assertSame(g, g.fork());
1208                 FibAction f = new FibAction(8);
1209                 assertSame(f, f.fork());
1210                 assertSame(g, pollTask());
1211                 helpQuiesce();
1212                 checkCompletedNormally(f);
1213                 checkNotDone(g);
1214             }};
1215         testInvokeOnPool(asyncSingletonPool(), a);
1216     }
1217 
1218     /** Demo from RecursiveAction javadoc */
1219     static class SortTask extends RecursiveAction {
1220         final long[] array; final int lo, hi;
1221         SortTask(long[] array, int lo, int hi) {
1222             this.array = array; this.lo = lo; this.hi = hi;
1223         }
1224         SortTask(long[] array) { this(array, 0, array.length); }
1225         protected void compute() {
1226             if (hi - lo < THRESHOLD)
1227                 sortSequentially(lo, hi);
1228             else {
1229                 int mid = (lo + hi) >>> 1;
1230                 invokeAll(new SortTask(array, lo, mid),
1231                           new SortTask(array, mid, hi));
1232                 merge(lo, mid, hi);
1233             }
1234         }
1235         // implementation details follow:
1236         static final int THRESHOLD = 100;
1237         void sortSequentially(int lo, int hi) {
1238             Arrays.sort(array, lo, hi);
1239         }
1240         void merge(int lo, int mid, int hi) {
1241             long[] buf = Arrays.copyOfRange(array, lo, mid);
1242             for (int i = 0, j = lo, k = mid; i < buf.length; j++)
1243                 array[j] = (k == hi || buf[i] < array[k]) ?
1244                     buf[i++] : array[k++];
1245         }
1246     }
1247 
1248     /**
1249      * SortTask demo works as advertised
1250      */
1251     public void testSortTaskDemo() {
1252         ThreadLocalRandom rnd = ThreadLocalRandom.current();
1253         long[] array = new long[1007];
1254         for (int i = 0; i < array.length; i++)
1255             array[i] = rnd.nextLong();
1256         long[] arrayClone = array.clone();
1257         testInvokeOnPool(mainPool(), new SortTask(array));
1258         Arrays.sort(arrayClone);
1259         assertTrue(Arrays.equals(array, arrayClone));
1260     }
1261 }