3 |
|
* Expert Group and released to the public domain, as explained at |
4 |
|
* http://creativecommons.org/publicdomain/zero/1.0/ |
5 |
|
*/ |
6 |
< |
import java.util.concurrent.ExecutionException; |
6 |
> |
|
7 |
> |
import static java.util.concurrent.TimeUnit.MILLISECONDS; |
8 |
> |
|
9 |
> |
import java.util.HashSet; |
10 |
|
import java.util.concurrent.CancellationException; |
11 |
+ |
import java.util.concurrent.CountedCompleter; |
12 |
+ |
import java.util.concurrent.ExecutionException; |
13 |
|
import java.util.concurrent.ForkJoinPool; |
14 |
|
import java.util.concurrent.ForkJoinTask; |
10 |
– |
import java.util.concurrent.CountedCompleter; |
11 |
– |
import java.util.concurrent.ForkJoinWorkerThread; |
12 |
– |
import java.util.concurrent.RecursiveAction; |
13 |
– |
import java.util.concurrent.TimeUnit; |
15 |
|
import java.util.concurrent.TimeoutException; |
16 |
|
import java.util.concurrent.atomic.AtomicInteger; |
16 |
– |
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; |
17 |
|
import java.util.concurrent.atomic.AtomicReference; |
18 |
< |
import static java.util.concurrent.TimeUnit.MILLISECONDS; |
19 |
< |
import static java.util.concurrent.TimeUnit.SECONDS; |
20 |
< |
import java.util.HashSet; |
21 |
< |
import junit.framework.*; |
18 |
> |
|
19 |
> |
import junit.framework.Test; |
20 |
> |
import junit.framework.TestSuite; |
21 |
|
|
22 |
|
public class CountedCompleterTest extends JSR166TestCase { |
23 |
|
|
24 |
|
public static void main(String[] args) { |
25 |
< |
junit.textui.TestRunner.run(suite()); |
25 |
> |
main(suite(), args); |
26 |
|
} |
27 |
|
|
28 |
|
public static Test suite() { |
48 |
|
} |
49 |
|
|
50 |
|
private void testInvokeOnPool(ForkJoinPool pool, ForkJoinTask a) { |
51 |
< |
try { |
51 |
> |
try (PoolCleaner cleaner = cleaner(pool)) { |
52 |
|
assertFalse(a.isDone()); |
53 |
|
assertFalse(a.isCompletedNormally()); |
54 |
|
assertFalse(a.isCompletedAbnormally()); |
64 |
|
assertFalse(a.isCancelled()); |
65 |
|
assertNull(a.getException()); |
66 |
|
assertNull(a.getRawResult()); |
68 |
– |
} finally { |
69 |
– |
joinPool(pool); |
67 |
|
} |
68 |
|
} |
69 |
|
|
76 |
|
assertNull(a.getRawResult()); |
77 |
|
|
78 |
|
try { |
79 |
< |
a.get(0L, SECONDS); |
79 |
> |
a.get(randomExpiredTimeout(), randomTimeUnit()); |
80 |
|
shouldThrow(); |
81 |
|
} catch (TimeoutException success) { |
82 |
|
} catch (Throwable fail) { threadUnexpectedException(fail); } |
92 |
|
|
93 |
|
{ |
94 |
|
Thread.currentThread().interrupt(); |
95 |
< |
long t0 = System.nanoTime(); |
95 |
> |
long startTime = System.nanoTime(); |
96 |
|
assertNull(a.join()); |
97 |
< |
assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS); |
97 |
> |
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); |
98 |
|
Thread.interrupted(); |
99 |
|
} |
100 |
|
|
101 |
|
{ |
102 |
|
Thread.currentThread().interrupt(); |
103 |
< |
long t0 = System.nanoTime(); |
103 |
> |
long startTime = System.nanoTime(); |
104 |
|
a.quietlyJoin(); // should be no-op |
105 |
< |
assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS); |
105 |
> |
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); |
106 |
|
Thread.interrupted(); |
107 |
|
} |
108 |
|
|
110 |
|
assertFalse(a.cancel(true)); |
111 |
|
try { |
112 |
|
assertNull(a.get()); |
113 |
< |
} catch (Throwable fail) { threadUnexpectedException(fail); } |
117 |
< |
try { |
118 |
< |
assertNull(a.get(5L, SECONDS)); |
113 |
> |
assertNull(a.get(randomTimeout(), randomTimeUnit())); |
114 |
|
} catch (Throwable fail) { threadUnexpectedException(fail); } |
115 |
|
} |
116 |
|
|
133 |
|
Thread.interrupted(); |
134 |
|
|
135 |
|
{ |
136 |
< |
long t0 = System.nanoTime(); |
136 |
> |
long startTime = System.nanoTime(); |
137 |
|
a.quietlyJoin(); // should be no-op |
138 |
< |
assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS); |
138 |
> |
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); |
139 |
|
} |
140 |
|
|
141 |
|
try { |
145 |
|
} catch (Throwable fail) { threadUnexpectedException(fail); } |
146 |
|
|
147 |
|
try { |
148 |
< |
a.get(5L, SECONDS); |
148 |
> |
a.get(randomTimeout(), randomTimeUnit()); |
149 |
|
shouldThrow(); |
150 |
|
} catch (CancellationException success) { |
151 |
|
} catch (Throwable fail) { threadUnexpectedException(fail); } |
171 |
|
Thread.interrupted(); |
172 |
|
|
173 |
|
{ |
174 |
< |
long t0 = System.nanoTime(); |
174 |
> |
long startTime = System.nanoTime(); |
175 |
|
a.quietlyJoin(); // should be no-op |
176 |
< |
assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS); |
176 |
> |
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); |
177 |
|
} |
178 |
|
|
179 |
|
try { |
184 |
|
} catch (Throwable fail) { threadUnexpectedException(fail); } |
185 |
|
|
186 |
|
try { |
187 |
< |
a.get(5L, SECONDS); |
187 |
> |
a.get(randomTimeout(), randomTimeUnit()); |
188 |
|
shouldThrow(); |
189 |
|
} catch (ExecutionException success) { |
190 |
|
assertSame(t.getClass(), success.getCause().getClass()); |
193 |
|
try { |
194 |
|
a.invoke(); |
195 |
|
shouldThrow(); |
196 |
< |
} catch (Throwable ex) { |
197 |
< |
assertSame(t, ex); |
196 |
> |
} catch (Throwable success) { |
197 |
> |
assertSame(t, success); |
198 |
|
} |
199 |
|
} |
200 |
|
|
247 |
|
} |
248 |
|
void checkCompletes(Object rawResult) { |
249 |
|
checkIncomplete(); |
250 |
+ |
int pendingCount = getPendingCount(); |
251 |
|
complete(rawResult); |
252 |
+ |
assertEquals(pendingCount, getPendingCount()); |
253 |
|
assertEquals(0, computeN()); |
254 |
|
assertEquals(1, onCompletionN()); |
255 |
|
assertEquals(0, onExceptionalCompletionN()); |
275 |
|
final class NoopCC extends CheckedCC { |
276 |
|
NoopCC() { super(); } |
277 |
|
NoopCC(CountedCompleter p) { super(p); } |
278 |
+ |
NoopCC(CountedCompleter p, int initialPendingCount) { |
279 |
+ |
super(p, initialPendingCount); |
280 |
+ |
} |
281 |
|
protected void realCompute() {} |
282 |
|
} |
283 |
|
|
284 |
|
/** |
285 |
|
* A newly constructed CountedCompleter is not completed; |
286 |
< |
* complete() causes completion. |
286 |
> |
* complete() causes completion. pendingCount is ignored. |
287 |
|
*/ |
288 |
|
public void testComplete() { |
289 |
|
for (Object x : new Object[] { Boolean.TRUE, null }) { |
290 |
< |
new NoopCC() |
291 |
< |
.checkCompletes(x); |
292 |
< |
new NoopCC(new NoopCC()) |
293 |
< |
.checkCompletes(x); |
290 |
> |
for (int pendingCount : new int[] { 0, 42 }) { |
291 |
> |
testComplete(new NoopCC(), x, pendingCount); |
292 |
> |
testComplete(new NoopCC(new NoopCC()), x, pendingCount); |
293 |
> |
} |
294 |
|
} |
295 |
|
} |
296 |
+ |
void testComplete(NoopCC cc, Object x, int pendingCount) { |
297 |
+ |
cc.setPendingCount(pendingCount); |
298 |
+ |
cc.checkCompletes(x); |
299 |
+ |
assertEquals(pendingCount, cc.getPendingCount()); |
300 |
+ |
} |
301 |
|
|
302 |
|
/** |
303 |
|
* completeExceptionally completes exceptionally |
310 |
|
} |
311 |
|
|
312 |
|
/** |
313 |
< |
* completeExceptionally(null) throws NullPointerException |
313 |
> |
* completeExceptionally(null) surprisingly has the same effect as |
314 |
> |
* completeExceptionally(new RuntimeException()) |
315 |
|
*/ |
316 |
|
public void testCompleteExceptionally_null() { |
317 |
+ |
NoopCC a = new NoopCC(); |
318 |
+ |
a.completeExceptionally(null); |
319 |
|
try { |
320 |
< |
new NoopCC() |
313 |
< |
.checkCompletesExceptionally(null); |
320 |
> |
a.invoke(); |
321 |
|
shouldThrow(); |
322 |
< |
} catch (NullPointerException success) {} |
322 |
> |
} catch (RuntimeException success) { |
323 |
> |
assertSame(success.getClass(), RuntimeException.class); |
324 |
> |
assertNull(success.getCause()); |
325 |
> |
a.checkCompletedExceptionally(success); |
326 |
> |
} |
327 |
|
} |
328 |
|
|
329 |
|
/** |
332 |
|
public void testSetPendingCount() { |
333 |
|
NoopCC a = new NoopCC(); |
334 |
|
assertEquals(0, a.getPendingCount()); |
335 |
< |
a.setPendingCount(1); |
336 |
< |
assertEquals(1, a.getPendingCount()); |
337 |
< |
a.setPendingCount(27); |
338 |
< |
assertEquals(27, a.getPendingCount()); |
335 |
> |
int[] vals = { |
336 |
> |
-1, 0, 1, |
337 |
> |
Integer.MIN_VALUE, |
338 |
> |
Integer.MAX_VALUE, |
339 |
> |
}; |
340 |
> |
for (int val : vals) { |
341 |
> |
a.setPendingCount(val); |
342 |
> |
assertEquals(val, a.getPendingCount()); |
343 |
> |
} |
344 |
|
} |
345 |
|
|
346 |
|
/** |
353 |
|
assertEquals(1, a.getPendingCount()); |
354 |
|
a.addToPendingCount(27); |
355 |
|
assertEquals(28, a.getPendingCount()); |
356 |
+ |
a.addToPendingCount(-28); |
357 |
+ |
assertEquals(0, a.getPendingCount()); |
358 |
|
} |
359 |
|
|
360 |
|
/** |
361 |
|
* decrementPendingCountUnlessZero decrements reported pending |
362 |
|
* count unless zero |
363 |
|
*/ |
364 |
< |
public void testDecrementPendingCount() { |
365 |
< |
NoopCC a = new NoopCC(); |
366 |
< |
assertEquals(0, a.getPendingCount()); |
367 |
< |
a.addToPendingCount(1); |
364 |
> |
public void testDecrementPendingCountUnlessZero() { |
365 |
> |
NoopCC a = new NoopCC(null, 2); |
366 |
> |
assertEquals(2, a.getPendingCount()); |
367 |
> |
assertEquals(2, a.decrementPendingCountUnlessZero()); |
368 |
|
assertEquals(1, a.getPendingCount()); |
369 |
< |
a.decrementPendingCountUnlessZero(); |
369 |
> |
assertEquals(1, a.decrementPendingCountUnlessZero()); |
370 |
|
assertEquals(0, a.getPendingCount()); |
371 |
< |
a.decrementPendingCountUnlessZero(); |
371 |
> |
assertEquals(0, a.decrementPendingCountUnlessZero()); |
372 |
|
assertEquals(0, a.getPendingCount()); |
373 |
+ |
a.setPendingCount(-1); |
374 |
+ |
assertEquals(-1, a.decrementPendingCountUnlessZero()); |
375 |
+ |
assertEquals(-2, a.getPendingCount()); |
376 |
|
} |
377 |
|
|
378 |
|
/** |
496 |
|
} |
497 |
|
|
498 |
|
/** |
499 |
< |
* quietlyCompleteRoot completes root task |
499 |
> |
* quietlyCompleteRoot completes root task and only root task |
500 |
|
*/ |
501 |
|
public void testQuietlyCompleteRoot() { |
502 |
|
NoopCC a = new NoopCC(); |
514 |
|
// Invocation tests use some interdependent task classes |
515 |
|
// to better test propagation etc |
516 |
|
|
517 |
< |
|
518 |
< |
// Version of Fibonacci with different classes for left vs right forks |
517 |
> |
/** |
518 |
> |
* Version of Fibonacci with different classes for left vs right forks |
519 |
> |
*/ |
520 |
|
abstract class CCF extends CheckedCC { |
521 |
|
int number; |
522 |
|
int rnumber; |
699 |
|
CCF f = new LCCF(8); |
700 |
|
assertSame(f, f.fork()); |
701 |
|
try { |
702 |
< |
f.get(5L, null); |
702 |
> |
f.get(randomTimeout(), null); |
703 |
|
shouldThrow(); |
704 |
|
} catch (NullPointerException success) {} |
705 |
|
}}; |
1152 |
|
} |
1153 |
|
|
1154 |
|
/** |
1155 |
< |
* invokeAll(collection) throws exception if any task does |
1155 |
> |
* invokeAll(collection) throws exception if any task does |
1156 |
|
*/ |
1157 |
|
public void testAbnormalInvokeAllCollection() { |
1158 |
|
ForkJoinTask a = new CheckedRecursiveAction() { |
1421 |
|
CCF f = new LCCF(8); |
1422 |
|
assertSame(f, f.fork()); |
1423 |
|
try { |
1424 |
< |
f.get(5L, null); |
1424 |
> |
f.get(randomTimeout(), null); |
1425 |
|
shouldThrow(); |
1426 |
|
} catch (NullPointerException success) {} |
1427 |
|
}}; |
1817 |
|
} |
1818 |
|
|
1819 |
|
/** |
1820 |
< |
* invokeAll(collection) throws exception if any task does |
1820 |
> |
* invokeAll(collection) throws exception if any task does |
1821 |
|
*/ |
1822 |
|
public void testAbnormalInvokeAllCollectionSingleton() { |
1823 |
|
ForkJoinTask a = new CheckedRecursiveAction() { |