author | dl |
Tue, 03 Oct 2017 13:55:05 -0700 | |
changeset 47306 | 90b7465b9ac7 |
parent 47216 | 71c04702a3d5 |
child 48541 | 946e34c2dec9 |
permissions | -rw-r--r-- |
35394 | 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 |
* Other contributors include Andrew Wright, Jeffrey Hayes, |
|
33 |
* Pat Fisher, Mike Judd. |
|
34 |
*/ |
|
35 |
||
36 |
import static java.util.concurrent.TimeUnit.MILLISECONDS; |
|
37 |
import static java.util.concurrent.TimeUnit.NANOSECONDS; |
|
38 |
||
39 |
import java.util.ArrayList; |
|
40 |
import java.util.List; |
|
41 |
import java.util.NoSuchElementException; |
|
42 |
import java.util.concurrent.Callable; |
|
43 |
import java.util.concurrent.CancellationException; |
|
44 |
import java.util.concurrent.CountDownLatch; |
|
45 |
import java.util.concurrent.ExecutionException; |
|
46 |
import java.util.concurrent.Executors; |
|
47 |
import java.util.concurrent.ExecutorService; |
|
48 |
import java.util.concurrent.Future; |
|
49 |
import java.util.concurrent.FutureTask; |
|
50 |
import java.util.concurrent.TimeoutException; |
|
51 |
import java.util.concurrent.atomic.AtomicInteger; |
|
52 |
||
53 |
import junit.framework.Test; |
|
54 |
import junit.framework.TestSuite; |
|
55 |
||
56 |
public class FutureTaskTest extends JSR166TestCase { |
|
57 |
||
58 |
public static void main(String[] args) { |
|
59 |
main(suite(), args); |
|
60 |
} |
|
61 |
public static Test suite() { |
|
62 |
return new TestSuite(FutureTaskTest.class); |
|
63 |
} |
|
64 |
||
65 |
void checkIsDone(Future<?> f) { |
|
66 |
assertTrue(f.isDone()); |
|
67 |
assertFalse(f.cancel(false)); |
|
68 |
assertFalse(f.cancel(true)); |
|
69 |
if (f instanceof PublicFutureTask) { |
|
70 |
PublicFutureTask pf = (PublicFutureTask) f; |
|
71 |
assertEquals(1, pf.doneCount()); |
|
72 |
assertFalse(pf.runAndReset()); |
|
73 |
assertEquals(1, pf.doneCount()); |
|
74 |
Object r = null; Object exInfo = null; |
|
75 |
try { |
|
76 |
r = f.get(); |
|
77 |
} catch (CancellationException t) { |
|
78 |
exInfo = CancellationException.class; |
|
79 |
} catch (ExecutionException t) { |
|
80 |
exInfo = t.getCause(); |
|
81 |
} catch (Throwable t) { |
|
82 |
threadUnexpectedException(t); |
|
83 |
} |
|
84 |
||
85 |
// Check that run and runAndReset have no effect. |
|
86 |
int savedRunCount = pf.runCount(); |
|
87 |
pf.run(); |
|
88 |
pf.runAndReset(); |
|
89 |
assertEquals(savedRunCount, pf.runCount()); |
|
90 |
try { |
|
91 |
assertSame(r, f.get()); |
|
92 |
} catch (CancellationException t) { |
|
93 |
assertSame(exInfo, CancellationException.class); |
|
94 |
} catch (ExecutionException t) { |
|
95 |
assertSame(exInfo, t.getCause()); |
|
96 |
} catch (Throwable t) { |
|
97 |
threadUnexpectedException(t); |
|
98 |
} |
|
99 |
assertTrue(f.isDone()); |
|
100 |
} |
|
101 |
} |
|
102 |
||
103 |
void checkNotDone(Future<?> f) { |
|
104 |
assertFalse(f.isDone()); |
|
105 |
assertFalse(f.isCancelled()); |
|
106 |
if (f instanceof PublicFutureTask) { |
|
107 |
PublicFutureTask pf = (PublicFutureTask) f; |
|
108 |
assertEquals(0, pf.doneCount()); |
|
109 |
assertEquals(0, pf.setCount()); |
|
110 |
assertEquals(0, pf.setExceptionCount()); |
|
111 |
} |
|
112 |
} |
|
113 |
||
114 |
void checkIsRunning(Future<?> f) { |
|
115 |
checkNotDone(f); |
|
116 |
if (f instanceof FutureTask) { |
|
117 |
FutureTask ft = (FutureTask<?>) f; |
|
118 |
// Check that run methods do nothing |
|
119 |
ft.run(); |
|
120 |
if (f instanceof PublicFutureTask) { |
|
121 |
PublicFutureTask pf = (PublicFutureTask) f; |
|
122 |
int savedRunCount = pf.runCount(); |
|
123 |
pf.run(); |
|
124 |
assertFalse(pf.runAndReset()); |
|
125 |
assertEquals(savedRunCount, pf.runCount()); |
|
126 |
} |
|
127 |
checkNotDone(f); |
|
128 |
} |
|
129 |
} |
|
130 |
||
131 |
<T> void checkCompletedNormally(Future<T> f, T expected) { |
|
132 |
checkIsDone(f); |
|
133 |
assertFalse(f.isCancelled()); |
|
134 |
||
135 |
try { |
|
136 |
assertSame(expected, f.get()); |
|
45937
646816090183
8178409: Miscellaneous changes imported from jsr166 CVS 2017-07
dl
parents:
35394
diff
changeset
|
137 |
assertSame(expected, f.get(randomTimeout(), randomTimeUnit())); |
35394 | 138 |
} catch (Throwable fail) { threadUnexpectedException(fail); } |
139 |
} |
|
140 |
||
141 |
void checkCancelled(Future<?> f) { |
|
142 |
checkIsDone(f); |
|
143 |
assertTrue(f.isCancelled()); |
|
144 |
||
145 |
try { |
|
146 |
f.get(); |
|
147 |
shouldThrow(); |
|
148 |
} catch (CancellationException success) { |
|
149 |
} catch (Throwable fail) { threadUnexpectedException(fail); } |
|
150 |
||
151 |
try { |
|
45937
646816090183
8178409: Miscellaneous changes imported from jsr166 CVS 2017-07
dl
parents:
35394
diff
changeset
|
152 |
f.get(randomTimeout(), randomTimeUnit()); |
35394 | 153 |
shouldThrow(); |
154 |
} catch (CancellationException success) { |
|
155 |
} catch (Throwable fail) { threadUnexpectedException(fail); } |
|
156 |
} |
|
157 |
||
158 |
void tryToConfuseDoneTask(PublicFutureTask pf) { |
|
159 |
pf.set(new Object()); |
|
160 |
pf.setException(new Error()); |
|
161 |
for (boolean mayInterruptIfRunning : new boolean[] { true, false }) { |
|
162 |
pf.cancel(mayInterruptIfRunning); |
|
163 |
} |
|
164 |
} |
|
165 |
||
166 |
void checkCompletedAbnormally(Future<?> f, Throwable t) { |
|
167 |
checkIsDone(f); |
|
168 |
assertFalse(f.isCancelled()); |
|
169 |
||
170 |
try { |
|
171 |
f.get(); |
|
172 |
shouldThrow(); |
|
173 |
} catch (ExecutionException success) { |
|
174 |
assertSame(t, success.getCause()); |
|
175 |
} catch (Throwable fail) { threadUnexpectedException(fail); } |
|
176 |
||
177 |
try { |
|
45937
646816090183
8178409: Miscellaneous changes imported from jsr166 CVS 2017-07
dl
parents:
35394
diff
changeset
|
178 |
f.get(randomTimeout(), randomTimeUnit()); |
35394 | 179 |
shouldThrow(); |
180 |
} catch (ExecutionException success) { |
|
181 |
assertSame(t, success.getCause()); |
|
182 |
} catch (Throwable fail) { threadUnexpectedException(fail); } |
|
183 |
} |
|
184 |
||
185 |
/** |
|
186 |
* Subclass to expose protected methods |
|
187 |
*/ |
|
188 |
static class PublicFutureTask extends FutureTask { |
|
189 |
private final AtomicInteger runCount; |
|
190 |
private final AtomicInteger doneCount = new AtomicInteger(0); |
|
191 |
private final AtomicInteger runAndResetCount = new AtomicInteger(0); |
|
192 |
private final AtomicInteger setCount = new AtomicInteger(0); |
|
193 |
private final AtomicInteger setExceptionCount = new AtomicInteger(0); |
|
194 |
public int runCount() { return runCount.get(); } |
|
195 |
public int doneCount() { return doneCount.get(); } |
|
196 |
public int runAndResetCount() { return runAndResetCount.get(); } |
|
197 |
public int setCount() { return setCount.get(); } |
|
198 |
public int setExceptionCount() { return setExceptionCount.get(); } |
|
199 |
||
200 |
PublicFutureTask(Runnable runnable) { |
|
201 |
this(runnable, seven); |
|
202 |
} |
|
203 |
PublicFutureTask(Runnable runnable, Object result) { |
|
204 |
this(runnable, result, new AtomicInteger(0)); |
|
205 |
} |
|
206 |
private PublicFutureTask(final Runnable runnable, Object result, |
|
207 |
final AtomicInteger runCount) { |
|
208 |
super(new Runnable() { |
|
209 |
public void run() { |
|
210 |
runCount.getAndIncrement(); |
|
211 |
runnable.run(); |
|
212 |
}}, result); |
|
213 |
this.runCount = runCount; |
|
214 |
} |
|
215 |
PublicFutureTask(Callable callable) { |
|
216 |
this(callable, new AtomicInteger(0)); |
|
217 |
} |
|
218 |
private PublicFutureTask(final Callable callable, |
|
219 |
final AtomicInteger runCount) { |
|
220 |
super(new Callable() { |
|
221 |
public Object call() throws Exception { |
|
222 |
runCount.getAndIncrement(); |
|
223 |
return callable.call(); |
|
224 |
}}); |
|
225 |
this.runCount = runCount; |
|
226 |
} |
|
227 |
@Override public void done() { |
|
228 |
assertTrue(isDone()); |
|
229 |
doneCount.incrementAndGet(); |
|
230 |
super.done(); |
|
231 |
} |
|
232 |
@Override public boolean runAndReset() { |
|
233 |
runAndResetCount.incrementAndGet(); |
|
234 |
return super.runAndReset(); |
|
235 |
} |
|
236 |
@Override public void set(Object x) { |
|
237 |
setCount.incrementAndGet(); |
|
238 |
super.set(x); |
|
239 |
} |
|
240 |
@Override public void setException(Throwable t) { |
|
241 |
setExceptionCount.incrementAndGet(); |
|
242 |
super.setException(t); |
|
243 |
} |
|
244 |
} |
|
245 |
||
246 |
class Counter extends CheckedRunnable { |
|
247 |
final AtomicInteger count = new AtomicInteger(0); |
|
248 |
public int get() { return count.get(); } |
|
249 |
public void realRun() { |
|
250 |
count.getAndIncrement(); |
|
251 |
} |
|
252 |
} |
|
253 |
||
254 |
/** |
|
255 |
* creating a future with a null callable throws NullPointerException |
|
256 |
*/ |
|
257 |
public void testConstructor() { |
|
258 |
try { |
|
259 |
new FutureTask(null); |
|
260 |
shouldThrow(); |
|
261 |
} catch (NullPointerException success) {} |
|
262 |
} |
|
263 |
||
264 |
/** |
|
265 |
* creating a future with null runnable throws NullPointerException |
|
266 |
*/ |
|
267 |
public void testConstructor2() { |
|
268 |
try { |
|
269 |
new FutureTask(null, Boolean.TRUE); |
|
270 |
shouldThrow(); |
|
271 |
} catch (NullPointerException success) {} |
|
272 |
} |
|
273 |
||
274 |
/** |
|
275 |
* isDone is true when a task completes |
|
276 |
*/ |
|
277 |
public void testIsDone() { |
|
278 |
PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); |
|
279 |
assertFalse(task.isDone()); |
|
280 |
task.run(); |
|
281 |
assertTrue(task.isDone()); |
|
282 |
checkCompletedNormally(task, Boolean.TRUE); |
|
283 |
assertEquals(1, task.runCount()); |
|
284 |
} |
|
285 |
||
286 |
/** |
|
287 |
* runAndReset of a non-cancelled task succeeds |
|
288 |
*/ |
|
289 |
public void testRunAndReset() { |
|
290 |
PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); |
|
291 |
for (int i = 0; i < 3; i++) { |
|
292 |
assertTrue(task.runAndReset()); |
|
293 |
checkNotDone(task); |
|
294 |
assertEquals(i + 1, task.runCount()); |
|
295 |
assertEquals(i + 1, task.runAndResetCount()); |
|
296 |
assertEquals(0, task.setCount()); |
|
297 |
assertEquals(0, task.setExceptionCount()); |
|
298 |
} |
|
299 |
} |
|
300 |
||
301 |
/** |
|
302 |
* runAndReset after cancellation fails |
|
303 |
*/ |
|
304 |
public void testRunAndResetAfterCancel() { |
|
305 |
for (boolean mayInterruptIfRunning : new boolean[] { true, false }) { |
|
306 |
PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); |
|
307 |
assertTrue(task.cancel(mayInterruptIfRunning)); |
|
308 |
for (int i = 0; i < 3; i++) { |
|
309 |
assertFalse(task.runAndReset()); |
|
310 |
assertEquals(0, task.runCount()); |
|
311 |
assertEquals(i + 1, task.runAndResetCount()); |
|
312 |
assertEquals(0, task.setCount()); |
|
313 |
assertEquals(0, task.setExceptionCount()); |
|
314 |
} |
|
315 |
tryToConfuseDoneTask(task); |
|
316 |
checkCancelled(task); |
|
317 |
} |
|
318 |
} |
|
319 |
||
320 |
/** |
|
321 |
* setting value causes get to return it |
|
322 |
*/ |
|
323 |
public void testSet() throws Exception { |
|
324 |
PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); |
|
325 |
task.set(one); |
|
326 |
for (int i = 0; i < 3; i++) { |
|
327 |
assertSame(one, task.get()); |
|
328 |
assertSame(one, task.get(LONG_DELAY_MS, MILLISECONDS)); |
|
329 |
assertEquals(1, task.setCount()); |
|
330 |
} |
|
331 |
tryToConfuseDoneTask(task); |
|
332 |
checkCompletedNormally(task, one); |
|
333 |
assertEquals(0, task.runCount()); |
|
334 |
} |
|
335 |
||
336 |
/** |
|
337 |
* setException causes get to throw ExecutionException |
|
338 |
*/ |
|
339 |
public void testSetException_get() throws Exception { |
|
340 |
Exception nse = new NoSuchElementException(); |
|
341 |
PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); |
|
342 |
task.setException(nse); |
|
343 |
||
344 |
try { |
|
345 |
task.get(); |
|
346 |
shouldThrow(); |
|
347 |
} catch (ExecutionException success) { |
|
348 |
assertSame(nse, success.getCause()); |
|
349 |
checkCompletedAbnormally(task, nse); |
|
350 |
} |
|
351 |
||
352 |
try { |
|
353 |
task.get(LONG_DELAY_MS, MILLISECONDS); |
|
354 |
shouldThrow(); |
|
355 |
} catch (ExecutionException success) { |
|
356 |
assertSame(nse, success.getCause()); |
|
357 |
checkCompletedAbnormally(task, nse); |
|
358 |
} |
|
359 |
||
360 |
assertEquals(1, task.setExceptionCount()); |
|
361 |
assertEquals(0, task.setCount()); |
|
362 |
tryToConfuseDoneTask(task); |
|
363 |
checkCompletedAbnormally(task, nse); |
|
364 |
assertEquals(0, task.runCount()); |
|
365 |
} |
|
366 |
||
367 |
/** |
|
368 |
* cancel(false) before run succeeds |
|
369 |
*/ |
|
370 |
public void testCancelBeforeRun() { |
|
371 |
PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); |
|
372 |
assertTrue(task.cancel(false)); |
|
373 |
task.run(); |
|
374 |
assertEquals(0, task.runCount()); |
|
375 |
assertEquals(0, task.setCount()); |
|
376 |
assertEquals(0, task.setExceptionCount()); |
|
377 |
assertTrue(task.isCancelled()); |
|
378 |
assertTrue(task.isDone()); |
|
379 |
tryToConfuseDoneTask(task); |
|
380 |
assertEquals(0, task.runCount()); |
|
381 |
checkCancelled(task); |
|
382 |
} |
|
383 |
||
384 |
/** |
|
385 |
* cancel(true) before run succeeds |
|
386 |
*/ |
|
387 |
public void testCancelBeforeRun2() { |
|
388 |
PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); |
|
389 |
assertTrue(task.cancel(true)); |
|
390 |
task.run(); |
|
391 |
assertEquals(0, task.runCount()); |
|
392 |
assertEquals(0, task.setCount()); |
|
393 |
assertEquals(0, task.setExceptionCount()); |
|
394 |
assertTrue(task.isCancelled()); |
|
395 |
assertTrue(task.isDone()); |
|
396 |
tryToConfuseDoneTask(task); |
|
397 |
assertEquals(0, task.runCount()); |
|
398 |
checkCancelled(task); |
|
399 |
} |
|
400 |
||
401 |
/** |
|
402 |
* cancel(false) of a completed task fails |
|
403 |
*/ |
|
404 |
public void testCancelAfterRun() { |
|
405 |
PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); |
|
406 |
task.run(); |
|
407 |
assertFalse(task.cancel(false)); |
|
408 |
assertEquals(1, task.runCount()); |
|
409 |
assertEquals(1, task.setCount()); |
|
410 |
assertEquals(0, task.setExceptionCount()); |
|
411 |
tryToConfuseDoneTask(task); |
|
412 |
checkCompletedNormally(task, Boolean.TRUE); |
|
413 |
assertEquals(1, task.runCount()); |
|
414 |
} |
|
415 |
||
416 |
/** |
|
417 |
* cancel(true) of a completed task fails |
|
418 |
*/ |
|
419 |
public void testCancelAfterRun2() { |
|
420 |
PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); |
|
421 |
task.run(); |
|
422 |
assertFalse(task.cancel(true)); |
|
423 |
assertEquals(1, task.runCount()); |
|
424 |
assertEquals(1, task.setCount()); |
|
425 |
assertEquals(0, task.setExceptionCount()); |
|
426 |
tryToConfuseDoneTask(task); |
|
427 |
checkCompletedNormally(task, Boolean.TRUE); |
|
428 |
assertEquals(1, task.runCount()); |
|
429 |
} |
|
430 |
||
431 |
/** |
|
432 |
* cancel(true) interrupts a running task that subsequently succeeds |
|
433 |
*/ |
|
434 |
public void testCancelInterrupt() { |
|
435 |
final CountDownLatch pleaseCancel = new CountDownLatch(1); |
|
436 |
final PublicFutureTask task = |
|
437 |
new PublicFutureTask(new CheckedRunnable() { |
|
438 |
public void realRun() { |
|
439 |
pleaseCancel.countDown(); |
|
440 |
try { |
|
441 |
delay(LONG_DELAY_MS); |
|
442 |
shouldThrow(); |
|
443 |
} catch (InterruptedException success) {} |
|
45937
646816090183
8178409: Miscellaneous changes imported from jsr166 CVS 2017-07
dl
parents:
35394
diff
changeset
|
444 |
assertFalse(Thread.interrupted()); |
35394 | 445 |
}}); |
446 |
||
447 |
Thread t = newStartedThread(task); |
|
448 |
await(pleaseCancel); |
|
449 |
assertTrue(task.cancel(true)); |
|
450 |
assertTrue(task.isCancelled()); |
|
451 |
assertTrue(task.isDone()); |
|
452 |
awaitTermination(t); |
|
453 |
assertEquals(1, task.runCount()); |
|
454 |
assertEquals(1, task.setCount()); |
|
455 |
assertEquals(0, task.setExceptionCount()); |
|
456 |
tryToConfuseDoneTask(task); |
|
457 |
checkCancelled(task); |
|
458 |
} |
|
459 |
||
460 |
/** |
|
461 |
* cancel(true) tries to interrupt a running task, but |
|
462 |
* Thread.interrupt throws (simulating a restrictive security |
|
463 |
* manager) |
|
464 |
*/ |
|
465 |
public void testCancelInterrupt_ThrowsSecurityException() { |
|
466 |
final CountDownLatch pleaseCancel = new CountDownLatch(1); |
|
467 |
final CountDownLatch cancelled = new CountDownLatch(1); |
|
468 |
final PublicFutureTask task = |
|
469 |
new PublicFutureTask(new CheckedRunnable() { |
|
470 |
public void realRun() { |
|
471 |
pleaseCancel.countDown(); |
|
472 |
await(cancelled); |
|
473 |
assertFalse(Thread.interrupted()); |
|
474 |
}}); |
|
475 |
||
476 |
final Thread t = new Thread(task) { |
|
477 |
// Simulate a restrictive security manager. |
|
478 |
@Override public void interrupt() { |
|
479 |
throw new SecurityException(); |
|
480 |
}}; |
|
481 |
t.setDaemon(true); |
|
482 |
t.start(); |
|
483 |
||
484 |
await(pleaseCancel); |
|
485 |
try { |
|
486 |
task.cancel(true); |
|
487 |
shouldThrow(); |
|
488 |
} catch (SecurityException expected) {} |
|
489 |
||
490 |
// We failed to deliver the interrupt, but the world retains |
|
491 |
// its sanity, as if we had done task.cancel(false) |
|
492 |
assertTrue(task.isCancelled()); |
|
493 |
assertTrue(task.isDone()); |
|
494 |
assertEquals(1, task.runCount()); |
|
495 |
assertEquals(1, task.doneCount()); |
|
496 |
assertEquals(0, task.setCount()); |
|
497 |
assertEquals(0, task.setExceptionCount()); |
|
498 |
cancelled.countDown(); |
|
499 |
awaitTermination(t); |
|
500 |
assertEquals(1, task.setCount()); |
|
501 |
assertEquals(0, task.setExceptionCount()); |
|
502 |
tryToConfuseDoneTask(task); |
|
503 |
checkCancelled(task); |
|
504 |
} |
|
505 |
||
506 |
/** |
|
507 |
* cancel(true) interrupts a running task that subsequently throws |
|
508 |
*/ |
|
509 |
public void testCancelInterrupt_taskFails() { |
|
510 |
final CountDownLatch pleaseCancel = new CountDownLatch(1); |
|
511 |
final PublicFutureTask task = |
|
512 |
new PublicFutureTask(new Runnable() { |
|
513 |
public void run() { |
|
514 |
pleaseCancel.countDown(); |
|
515 |
try { |
|
516 |
delay(LONG_DELAY_MS); |
|
517 |
threadShouldThrow(); |
|
518 |
} catch (InterruptedException success) { |
|
519 |
} catch (Throwable t) { threadUnexpectedException(t); } |
|
520 |
throw new RuntimeException(); |
|
521 |
}}); |
|
522 |
||
523 |
Thread t = newStartedThread(task); |
|
524 |
await(pleaseCancel); |
|
525 |
assertTrue(task.cancel(true)); |
|
526 |
assertTrue(task.isCancelled()); |
|
527 |
awaitTermination(t); |
|
528 |
assertEquals(1, task.runCount()); |
|
529 |
assertEquals(0, task.setCount()); |
|
530 |
assertEquals(1, task.setExceptionCount()); |
|
531 |
tryToConfuseDoneTask(task); |
|
532 |
checkCancelled(task); |
|
533 |
} |
|
534 |
||
535 |
/** |
|
536 |
* cancel(false) does not interrupt a running task |
|
537 |
*/ |
|
538 |
public void testCancelNoInterrupt() { |
|
539 |
final CountDownLatch pleaseCancel = new CountDownLatch(1); |
|
540 |
final CountDownLatch cancelled = new CountDownLatch(1); |
|
541 |
final PublicFutureTask task = |
|
542 |
new PublicFutureTask(new CheckedCallable<Boolean>() { |
|
543 |
public Boolean realCall() { |
|
544 |
pleaseCancel.countDown(); |
|
545 |
await(cancelled); |
|
546 |
assertFalse(Thread.interrupted()); |
|
547 |
return Boolean.TRUE; |
|
548 |
}}); |
|
549 |
||
550 |
Thread t = newStartedThread(task); |
|
551 |
await(pleaseCancel); |
|
552 |
assertTrue(task.cancel(false)); |
|
553 |
assertTrue(task.isCancelled()); |
|
554 |
cancelled.countDown(); |
|
555 |
awaitTermination(t); |
|
556 |
assertEquals(1, task.runCount()); |
|
557 |
assertEquals(1, task.setCount()); |
|
558 |
assertEquals(0, task.setExceptionCount()); |
|
559 |
tryToConfuseDoneTask(task); |
|
560 |
checkCancelled(task); |
|
561 |
} |
|
562 |
||
563 |
/** |
|
564 |
* run in one thread causes get in another thread to retrieve value |
|
565 |
*/ |
|
566 |
public void testGetRun() { |
|
567 |
final CountDownLatch pleaseRun = new CountDownLatch(2); |
|
568 |
||
569 |
final PublicFutureTask task = |
|
570 |
new PublicFutureTask(new CheckedCallable<Object>() { |
|
571 |
public Object realCall() { |
|
572 |
return two; |
|
573 |
}}); |
|
574 |
||
575 |
Thread t1 = newStartedThread(new CheckedRunnable() { |
|
576 |
public void realRun() throws Exception { |
|
577 |
pleaseRun.countDown(); |
|
578 |
assertSame(two, task.get()); |
|
579 |
}}); |
|
580 |
||
581 |
Thread t2 = newStartedThread(new CheckedRunnable() { |
|
582 |
public void realRun() throws Exception { |
|
583 |
pleaseRun.countDown(); |
|
584 |
assertSame(two, task.get(2*LONG_DELAY_MS, MILLISECONDS)); |
|
585 |
}}); |
|
586 |
||
587 |
await(pleaseRun); |
|
588 |
checkNotDone(task); |
|
589 |
assertTrue(t1.isAlive()); |
|
590 |
assertTrue(t2.isAlive()); |
|
591 |
task.run(); |
|
592 |
checkCompletedNormally(task, two); |
|
593 |
assertEquals(1, task.runCount()); |
|
594 |
assertEquals(1, task.setCount()); |
|
595 |
assertEquals(0, task.setExceptionCount()); |
|
596 |
awaitTermination(t1); |
|
597 |
awaitTermination(t2); |
|
598 |
tryToConfuseDoneTask(task); |
|
599 |
checkCompletedNormally(task, two); |
|
600 |
} |
|
601 |
||
602 |
/** |
|
603 |
* set in one thread causes get in another thread to retrieve value |
|
604 |
*/ |
|
605 |
public void testGetSet() { |
|
606 |
final CountDownLatch pleaseSet = new CountDownLatch(2); |
|
607 |
||
608 |
final PublicFutureTask task = |
|
609 |
new PublicFutureTask(new CheckedCallable<Object>() { |
|
610 |
public Object realCall() throws InterruptedException { |
|
611 |
return two; |
|
612 |
}}); |
|
613 |
||
614 |
Thread t1 = newStartedThread(new CheckedRunnable() { |
|
615 |
public void realRun() throws Exception { |
|
616 |
pleaseSet.countDown(); |
|
617 |
assertSame(two, task.get()); |
|
618 |
}}); |
|
619 |
||
620 |
Thread t2 = newStartedThread(new CheckedRunnable() { |
|
621 |
public void realRun() throws Exception { |
|
622 |
pleaseSet.countDown(); |
|
623 |
assertSame(two, task.get(2*LONG_DELAY_MS, MILLISECONDS)); |
|
624 |
}}); |
|
625 |
||
626 |
await(pleaseSet); |
|
627 |
checkNotDone(task); |
|
628 |
assertTrue(t1.isAlive()); |
|
629 |
assertTrue(t2.isAlive()); |
|
630 |
task.set(two); |
|
631 |
assertEquals(0, task.runCount()); |
|
632 |
assertEquals(1, task.setCount()); |
|
633 |
assertEquals(0, task.setExceptionCount()); |
|
634 |
tryToConfuseDoneTask(task); |
|
635 |
checkCompletedNormally(task, two); |
|
636 |
awaitTermination(t1); |
|
637 |
awaitTermination(t2); |
|
638 |
} |
|
639 |
||
640 |
/** |
|
641 |
* Cancelling a task causes timed get in another thread to throw |
|
642 |
* CancellationException |
|
643 |
*/ |
|
644 |
public void testTimedGet_Cancellation() { |
|
645 |
testTimedGet_Cancellation(false); |
|
646 |
} |
|
647 |
public void testTimedGet_Cancellation_interrupt() { |
|
648 |
testTimedGet_Cancellation(true); |
|
649 |
} |
|
650 |
public void testTimedGet_Cancellation(final boolean mayInterruptIfRunning) { |
|
651 |
final CountDownLatch pleaseCancel = new CountDownLatch(3); |
|
652 |
final CountDownLatch cancelled = new CountDownLatch(1); |
|
653 |
final Callable<Object> callable = |
|
654 |
new CheckedCallable<Object>() { |
|
655 |
public Object realCall() throws InterruptedException { |
|
656 |
pleaseCancel.countDown(); |
|
657 |
if (mayInterruptIfRunning) { |
|
658 |
try { |
|
659 |
delay(2*LONG_DELAY_MS); |
|
660 |
} catch (InterruptedException success) {} |
|
661 |
} else { |
|
662 |
await(cancelled); |
|
663 |
} |
|
664 |
return two; |
|
665 |
}}; |
|
666 |
final PublicFutureTask task = new PublicFutureTask(callable); |
|
667 |
||
668 |
Thread t1 = new ThreadShouldThrow(CancellationException.class) { |
|
669 |
public void realRun() throws Exception { |
|
670 |
pleaseCancel.countDown(); |
|
671 |
task.get(); |
|
672 |
}}; |
|
673 |
Thread t2 = new ThreadShouldThrow(CancellationException.class) { |
|
674 |
public void realRun() throws Exception { |
|
675 |
pleaseCancel.countDown(); |
|
676 |
task.get(2*LONG_DELAY_MS, MILLISECONDS); |
|
677 |
}}; |
|
678 |
t1.start(); |
|
679 |
t2.start(); |
|
680 |
Thread t3 = newStartedThread(task); |
|
681 |
await(pleaseCancel); |
|
682 |
checkIsRunning(task); |
|
683 |
task.cancel(mayInterruptIfRunning); |
|
684 |
checkCancelled(task); |
|
685 |
awaitTermination(t1); |
|
686 |
awaitTermination(t2); |
|
687 |
cancelled.countDown(); |
|
688 |
awaitTermination(t3); |
|
689 |
assertEquals(1, task.runCount()); |
|
690 |
assertEquals(1, task.setCount()); |
|
691 |
assertEquals(0, task.setExceptionCount()); |
|
692 |
tryToConfuseDoneTask(task); |
|
693 |
checkCancelled(task); |
|
694 |
} |
|
695 |
||
696 |
/** |
|
697 |
* A runtime exception in task causes get to throw ExecutionException |
|
698 |
*/ |
|
699 |
public void testGet_ExecutionException() throws InterruptedException { |
|
700 |
final ArithmeticException e = new ArithmeticException(); |
|
701 |
final PublicFutureTask task = new PublicFutureTask(new Callable() { |
|
702 |
public Object call() { |
|
703 |
throw e; |
|
704 |
}}); |
|
705 |
||
706 |
task.run(); |
|
707 |
assertEquals(1, task.runCount()); |
|
708 |
assertEquals(0, task.setCount()); |
|
709 |
assertEquals(1, task.setExceptionCount()); |
|
710 |
try { |
|
711 |
task.get(); |
|
712 |
shouldThrow(); |
|
713 |
} catch (ExecutionException success) { |
|
714 |
assertSame(e, success.getCause()); |
|
715 |
tryToConfuseDoneTask(task); |
|
716 |
checkCompletedAbnormally(task, success.getCause()); |
|
717 |
} |
|
718 |
} |
|
719 |
||
720 |
/** |
|
721 |
* A runtime exception in task causes timed get to throw ExecutionException |
|
722 |
*/ |
|
723 |
public void testTimedGet_ExecutionException2() throws Exception { |
|
724 |
final ArithmeticException e = new ArithmeticException(); |
|
725 |
final PublicFutureTask task = new PublicFutureTask(new Callable() { |
|
726 |
public Object call() { |
|
727 |
throw e; |
|
728 |
}}); |
|
729 |
||
730 |
task.run(); |
|
731 |
try { |
|
732 |
task.get(LONG_DELAY_MS, MILLISECONDS); |
|
733 |
shouldThrow(); |
|
734 |
} catch (ExecutionException success) { |
|
735 |
assertSame(e, success.getCause()); |
|
736 |
tryToConfuseDoneTask(task); |
|
737 |
checkCompletedAbnormally(task, success.getCause()); |
|
738 |
} |
|
739 |
} |
|
740 |
||
741 |
/** |
|
742 |
* get is interruptible |
|
743 |
*/ |
|
744 |
public void testGet_interruptible() { |
|
745 |
final CountDownLatch pleaseInterrupt = new CountDownLatch(1); |
|
746 |
final FutureTask task = new FutureTask(new NoOpCallable()); |
|
747 |
Thread t = newStartedThread(new CheckedRunnable() { |
|
748 |
public void realRun() throws Exception { |
|
749 |
Thread.currentThread().interrupt(); |
|
750 |
try { |
|
751 |
task.get(); |
|
752 |
shouldThrow(); |
|
753 |
} catch (InterruptedException success) {} |
|
754 |
assertFalse(Thread.interrupted()); |
|
755 |
||
756 |
pleaseInterrupt.countDown(); |
|
757 |
try { |
|
758 |
task.get(); |
|
759 |
shouldThrow(); |
|
760 |
} catch (InterruptedException success) {} |
|
761 |
assertFalse(Thread.interrupted()); |
|
762 |
}}); |
|
763 |
||
764 |
await(pleaseInterrupt); |
|
765 |
t.interrupt(); |
|
766 |
awaitTermination(t); |
|
767 |
checkNotDone(task); |
|
768 |
} |
|
769 |
||
770 |
/** |
|
771 |
* timed get is interruptible |
|
772 |
*/ |
|
773 |
public void testTimedGet_interruptible() { |
|
774 |
final CountDownLatch pleaseInterrupt = new CountDownLatch(1); |
|
775 |
final FutureTask task = new FutureTask(new NoOpCallable()); |
|
776 |
Thread t = newStartedThread(new CheckedRunnable() { |
|
777 |
public void realRun() throws Exception { |
|
778 |
Thread.currentThread().interrupt(); |
|
779 |
try { |
|
780 |
task.get(2*LONG_DELAY_MS, MILLISECONDS); |
|
781 |
shouldThrow(); |
|
782 |
} catch (InterruptedException success) {} |
|
783 |
assertFalse(Thread.interrupted()); |
|
784 |
||
785 |
pleaseInterrupt.countDown(); |
|
786 |
try { |
|
787 |
task.get(2*LONG_DELAY_MS, MILLISECONDS); |
|
788 |
shouldThrow(); |
|
789 |
} catch (InterruptedException success) {} |
|
790 |
assertFalse(Thread.interrupted()); |
|
791 |
}}); |
|
792 |
||
793 |
await(pleaseInterrupt); |
|
794 |
t.interrupt(); |
|
795 |
awaitTermination(t); |
|
796 |
checkNotDone(task); |
|
797 |
} |
|
798 |
||
799 |
/** |
|
800 |
* A timed out timed get throws TimeoutException |
|
801 |
*/ |
|
802 |
public void testGet_TimeoutException() throws Exception { |
|
803 |
FutureTask task = new FutureTask(new NoOpCallable()); |
|
804 |
long startTime = System.nanoTime(); |
|
805 |
try { |
|
806 |
task.get(timeoutMillis(), MILLISECONDS); |
|
807 |
shouldThrow(); |
|
808 |
} catch (TimeoutException success) { |
|
809 |
assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); |
|
810 |
} |
|
811 |
} |
|
812 |
||
813 |
/** |
|
814 |
* timed get with null TimeUnit throws NullPointerException |
|
815 |
*/ |
|
816 |
public void testGet_NullTimeUnit() throws Exception { |
|
817 |
FutureTask task = new FutureTask(new NoOpCallable()); |
|
818 |
long[] timeouts = { Long.MIN_VALUE, 0L, Long.MAX_VALUE }; |
|
819 |
||
820 |
for (long timeout : timeouts) { |
|
821 |
try { |
|
822 |
task.get(timeout, null); |
|
823 |
shouldThrow(); |
|
824 |
} catch (NullPointerException success) {} |
|
825 |
} |
|
826 |
||
827 |
task.run(); |
|
828 |
||
829 |
for (long timeout : timeouts) { |
|
830 |
try { |
|
831 |
task.get(timeout, null); |
|
832 |
shouldThrow(); |
|
833 |
} catch (NullPointerException success) {} |
|
834 |
} |
|
835 |
} |
|
836 |
||
837 |
/** |
|
838 |
* timed get with most negative timeout works correctly (i.e. no |
|
839 |
* underflow bug) |
|
840 |
*/ |
|
841 |
public void testGet_NegativeInfinityTimeout() throws Exception { |
|
842 |
final ExecutorService pool = Executors.newFixedThreadPool(10); |
|
843 |
final Runnable nop = new Runnable() { public void run() {}}; |
|
844 |
final FutureTask<Void> task = new FutureTask<>(nop, null); |
|
845 |
final List<Future<?>> futures = new ArrayList<>(); |
|
846 |
Runnable r = new Runnable() { public void run() { |
|
847 |
for (long timeout : new long[] { 0L, -1L, Long.MIN_VALUE }) { |
|
848 |
try { |
|
849 |
task.get(timeout, NANOSECONDS); |
|
850 |
shouldThrow(); |
|
851 |
} catch (TimeoutException success) { |
|
852 |
} catch (Throwable fail) {threadUnexpectedException(fail);}}}}; |
|
853 |
for (int i = 0; i < 10; i++) |
|
854 |
futures.add(pool.submit(r)); |
|
855 |
try { |
|
856 |
joinPool(pool); |
|
857 |
for (Future<?> future : futures) |
|
858 |
checkCompletedNormally(future, null); |
|
859 |
} finally { |
|
860 |
task.run(); // last resort to help terminate |
|
861 |
} |
|
862 |
} |
|
863 |
||
47306
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
864 |
/** |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
865 |
* toString indicates current completion state |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
866 |
*/ |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
867 |
public void testToString_incomplete() { |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
868 |
FutureTask<String> f = new FutureTask<String>(() -> ""); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
869 |
assertTrue(f.toString().matches(".*\\[.*Not completed.*\\]")); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
870 |
if (testImplementationDetails) |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
871 |
assertTrue(f.toString().startsWith( |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
872 |
identityString(f) + "[Not completed, task =")); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
873 |
} |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
874 |
|
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
875 |
public void testToString_normal() { |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
876 |
FutureTask<String> f = new FutureTask<String>(() -> ""); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
877 |
f.run(); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
878 |
assertTrue(f.toString().matches(".*\\[.*Completed normally.*\\]")); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
879 |
if (testImplementationDetails) |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
880 |
assertEquals(identityString(f) + "[Completed normally]", |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
881 |
f.toString()); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
882 |
} |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
883 |
|
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
884 |
public void testToString_exception() { |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
885 |
FutureTask<String> f = new FutureTask<String>( |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
886 |
() -> { throw new ArithmeticException(); }); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
887 |
f.run(); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
888 |
assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]")); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
889 |
if (testImplementationDetails) |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
890 |
assertTrue(f.toString().startsWith( |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
891 |
identityString(f) + "[Completed exceptionally: ")); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
892 |
} |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
893 |
|
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
894 |
public void testToString_cancelled() { |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
895 |
for (boolean mayInterruptIfRunning : new boolean[] { true, false }) { |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
896 |
FutureTask<String> f = new FutureTask<String>(() -> ""); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
897 |
assertTrue(f.cancel(mayInterruptIfRunning)); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
898 |
assertTrue(f.toString().matches(".*\\[.*Cancelled.*\\]")); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
899 |
if (testImplementationDetails) |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
900 |
assertEquals(identityString(f) + "[Cancelled]", |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
901 |
f.toString()); |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
902 |
} |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
903 |
} |
90b7465b9ac7
8186265: Make toString() methods of "task" objects more useful
dl
parents:
47216
diff
changeset
|
904 |
|
35394 | 905 |
} |