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 }