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