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