ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FutureTask.java
Revision: 1.16
Committed: Fri Dec 19 14:42:25 2003 UTC (20 years, 5 months ago) by dl
Branch: MAIN
Changes since 1.15: +2 -1 lines
Log Message:
Documentation improvements

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain. Use, modify, and
4 * redistribute this code in any way without acknowledgement.
5 */
6
7 package java.util.concurrent;
8 import java.util.concurrent.locks.*;
9
10
11 /**
12 * A cancellable asynchronous computation. This class provides a base
13 * implementation of {@link Future}, with methods to start and cancel
14 * a computation, query to see if the computation is complete, and
15 * retrieve the result of the computation. The result can only be
16 * retrieved when the computation has completed; the <tt>get</tt>
17 * method will block if the computation has not yet completed. Once
18 * the computation has completed, the computation cannot be restarted
19 * or cancelled.
20 *
21 * <p>A <tt>FutureTask</tt> can be used to wrap a {@link Callable} or
22 * {@link java.lang.Runnable} object. Because <tt>FutureTask</tt>
23 * implements <tt>Runnable</tt>, a <tt>FutureTask</tt> can be
24 * submitted to an {@link Executor} for execution.
25 *
26 * <p>In addition to serving as a standalone class, this class provides
27 * <tt>protected</tt> functionality that may be useful when creating
28 * customized task classes.
29 *
30 * @since 1.5
31 * @author Doug Lea
32 * @param <V> The result type returned by this FutureTask's <tt>get</tt> method
33 */
34 public class FutureTask<V> implements Future<V>, Runnable {
35 /**
36 * Special value for "runner" indicating task is cancelled
37 */
38 private static final Object CANCELLED = new Object();
39
40 /**
41 * Special value for "runner" indicating task is completed
42 */
43 private static final Object DONE = new Object();
44
45 /**
46 * Holds the run-state, taking on values:
47 * null = not yet started,
48 * [some thread ref] = running,
49 * DONE = completed normally,
50 * CANCELLED = cancelled (may or may not have ever run).
51 */
52 private volatile Object runner;
53
54 /*
55 * For simplicity of use, we can use either a Runnable or a
56 * Callable as basis for run method. So one or the other of these
57 * will be null.
58 */
59
60 /** The runnable; if non-null, then callable is null */
61 private final Runnable runnable;
62 /** The callable; if non-null, then runnable is null */
63 private final Callable<V> callable;
64
65 /** The result to return from get() */
66 private V result;
67 /** The exception to throw from get() */
68 private Throwable exception;
69
70 private final ReentrantLock lock = new ReentrantLock();
71 private final ReentrantLock.ConditionObject accessible = lock.newCondition();
72
73 /**
74 * Constructs a <tt>FutureTask</tt> that will upon running, execute the
75 * given <tt>Callable</tt>.
76 *
77 * @param callable the callable task
78 * @throws NullPointerException if callable is null
79 */
80 public FutureTask(Callable<V> callable) {
81 if (callable == null)
82 throw new NullPointerException();
83 this.callable = callable;
84 this.runnable = null;
85 }
86
87 /**
88 * Constructs a <tt>FutureTask</tt> that will upon running, execute the
89 * given <tt>Runnable</tt>, and arrange that <tt>get</tt> will return the
90 * given result on successful completion.
91 *
92 * @param runnable the runnable task
93 * @param result the result to return on successful completion. If
94 * you don't need a particular result, consider using
95 * constructions of the form:
96 * <tt>Future&lt;?&gt; f = new FutureTask&lt;Object&gt;(runnable, null)</tt>
97 * @throws NullPointerException if runnable is null
98 */
99 public FutureTask(Runnable runnable, V result) {
100 if (runnable == null)
101 throw new NullPointerException();
102 this.runnable = runnable;
103 this.result = result;
104 this.callable = null;
105 }
106
107 public boolean cancel(boolean mayInterruptIfRunning) {
108 lock.lock();
109 try {
110 Object r = runner;
111 if (r == DONE || r == CANCELLED)
112 return false;
113 if (mayInterruptIfRunning && r != null && r instanceof Thread)
114 ((Thread)r).interrupt();
115 runner = CANCELLED;
116 }
117 finally{
118 lock.unlock();
119 }
120 done();
121 return true;
122 }
123
124 public boolean isCancelled() {
125 return runner == CANCELLED;
126 }
127
128 public boolean isDone() {
129 Object r = runner;
130 return r == DONE || r == CANCELLED;
131 }
132
133 /**
134 * Waits if necessary for the call to <tt>callable.call</tt> to
135 * complete, and then retrieves its result.
136 *
137 * @return computed result
138 * @throws CancellationException if underlying computation was
139 * cancelled
140 * @throws ExecutionException if underlying computation threw an
141 * exception
142 * @throws InterruptedException if current thread was interrupted
143 * while waiting
144 */
145 public V get() throws InterruptedException, ExecutionException {
146 lock.lock();
147 try {
148 while (!isDone())
149 accessible.await();
150 if (isCancelled())
151 throw new CancellationException();
152 else if (exception != null)
153 throw new ExecutionException(exception);
154 else
155 return result;
156 } finally {
157 lock.unlock();
158 }
159 }
160
161 /**
162 * Waits if necessary for at most the given time for the call to
163 * <tt>callable.call</tt> to complete, and then retrieves its
164 * result.
165 *
166 * @param timeout the maximum time to wait
167 * @param unit the time unit of the timeout argument
168 * @return computed result
169 * @throws CancellationException if underlying computation was
170 * cancelled
171 * @throws ExecutionException if underlying computation threw an
172 * exception
173 * @throws InterruptedException if current thread was interrupted
174 * while waiting
175 * @throws TimeoutException if the wait timed out
176 */
177 public V get(long timeout, TimeUnit unit)
178 throws InterruptedException, ExecutionException, TimeoutException {
179 lock.lock();
180 try {
181 if (!isDone()) {
182 long nanos = unit.toNanos(timeout);
183 do {
184 if (nanos <= 0)
185 throw new TimeoutException();
186 nanos = accessible.awaitNanos(nanos);
187 } while (!isDone());
188 }
189 if (isCancelled())
190 throw new CancellationException();
191 else if (exception != null)
192 throw new ExecutionException(exception);
193 else
194 return result;
195 } finally {
196 lock.unlock();
197 }
198 }
199
200 /**
201 * Sets the result of this Future to the given value.
202 * @param v the value
203 */
204 protected void set(V v) {
205 lock.lock();
206 try {
207 result = v;
208 setDone();
209 accessible.signalAll();
210 } finally {
211 lock.unlock();
212 }
213 }
214
215 /**
216 * Causes this future to report an <tt>ExecutionException</tt>
217 * with the given throwable as its cause.
218 * @param t the cause of failure.
219 */
220 protected void setException(Throwable t) {
221 lock.lock();
222 try {
223 exception = t;
224 setDone();
225 accessible.signalAll();
226 } finally {
227 lock.unlock();
228 }
229 }
230
231 /**
232 * Sets the state of this task to Cancelled.
233 */
234 protected void setCancelled() {
235 lock.lock();
236 try {
237 runner = CANCELLED;
238 }
239 finally{
240 lock.unlock();
241 }
242 }
243
244 /**
245 * Sets the state of this task to Done, unless already in a
246 * Cancelled state, in which case Cancelled status is preserved.
247 */
248 protected void setDone() {
249 lock.lock();
250 try {
251 Object r = runner;
252 if (r == DONE || r == CANCELLED)
253 return;
254 runner = DONE;
255 }
256 finally{
257 lock.unlock();
258 }
259 done();
260 }
261
262 /**
263 * Attempts to set the state of this task to Running, succeeding
264 * only if the state is currently NOT Done, Running, or Cancelled.
265 * @return true if successful
266 */
267 protected boolean setRunning() {
268 lock.lock();
269 try {
270 if (runner != null)
271 return false;
272 runner = Thread.currentThread();
273 return true;
274 }
275 finally {
276 lock.unlock();
277 }
278 }
279
280 /**
281 * Sets this Future to the results of computation
282 */
283 public void run() {
284 if (setRunning()) {
285 try {
286 try {
287 if (runnable != null)
288 runnable.run();
289 else if (callable != null)
290 set(callable.call());
291 } catch(Throwable ex) {
292 setException(ex);
293 }
294 } finally {
295 setDone();
296 }
297 }
298 }
299
300 /**
301 * Sets this Future to the results of computation and then resets
302 * to initial state. This may be useful for tasks that must
303 * execute more than once.
304 */
305 protected void runAndReset() {
306 if (setRunning()) {
307 try {
308 try {
309 if (runnable != null)
310 runnable.run();
311 else if (callable != null)
312 set(callable.call());
313 } catch(Throwable ex) {
314 setException(ex);
315 }
316 } finally {
317 reset();
318 }
319 }
320 }
321
322 /**
323 * Protected method invoked when this task transitions to state
324 * <tt>isDone</tt> (whether normally or via cancellation). The
325 * default implementation does nothing. Subclasses may override
326 * this method to invoke completion callbacks or perform
327 * bookkeeping. Note that you can query status inside the
328 * implementation of this method to determine whether this task
329 * has been cancelled.
330 */
331 protected void done() { }
332
333 /**
334 * Resets the run state of this task to its initial state unless
335 * it has been cancelled. (Note that a cancelled task cannot be
336 * reset.)
337 * @return true if successful
338 */
339 protected boolean reset() {
340 lock.lock();
341 try {
342 if (runner == CANCELLED)
343 return false;
344 runner = null;
345 return true;
346 }
347 finally {
348 lock.unlock();
349 }
350 }
351
352 /**
353 * Return the <tt>Runnable</tt> or <tt>Callable</tt> used
354 * in the constructor for this <tt>Future</tt>.
355 * @return the task
356 */
357 protected Object getTask() {
358 if (runnable != null)
359 return runnable;
360 else
361 return callable;
362 }
363
364 }
365