ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FutureTask.java
Revision: 1.17
Committed: Sat Dec 20 18:57:32 2003 UTC (20 years, 5 months ago) by dl
Branch: MAIN
Changes since 1.16: +5 -6 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 execution to complete, and then
135 * 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 execution to
163 * complete, and then retrieves its result, if available.
164 *
165 * @param timeout the maximum time to wait
166 * @param unit the time unit of the timeout argument
167 * @return computed result
168 * @throws CancellationException if underlying computation was
169 * cancelled
170 * @throws ExecutionException if underlying computation threw an
171 * exception
172 * @throws InterruptedException if current thread was interrupted
173 * while waiting
174 * @throws TimeoutException if the wait timed out
175 */
176 public V get(long timeout, TimeUnit unit)
177 throws InterruptedException, ExecutionException, TimeoutException {
178 lock.lock();
179 try {
180 if (!isDone()) {
181 long nanos = unit.toNanos(timeout);
182 do {
183 if (nanos <= 0)
184 throw new TimeoutException();
185 nanos = accessible.awaitNanos(nanos);
186 } while (!isDone());
187 }
188 if (isCancelled())
189 throw new CancellationException();
190 else if (exception != null)
191 throw new ExecutionException(exception);
192 else
193 return result;
194 } finally {
195 lock.unlock();
196 }
197 }
198
199 /**
200 * Sets the result of this Future to the given value.
201 * @param v the value
202 */
203 protected void set(V v) {
204 lock.lock();
205 try {
206 result = v;
207 setDone();
208 accessible.signalAll();
209 } finally {
210 lock.unlock();
211 }
212 }
213
214 /**
215 * Causes this future to report an <tt>ExecutionException</tt>
216 * with the given throwable as its cause.
217 * @param t the cause of failure.
218 */
219 protected void setException(Throwable t) {
220 lock.lock();
221 try {
222 exception = t;
223 setDone();
224 accessible.signalAll();
225 } finally {
226 lock.unlock();
227 }
228 }
229
230 /**
231 * Sets the state of this task to Cancelled.
232 */
233 protected void setCancelled() {
234 lock.lock();
235 try {
236 runner = CANCELLED;
237 }
238 finally{
239 lock.unlock();
240 }
241 }
242
243 /**
244 * Sets the state of this task to Done, unless already in a
245 * Cancelled state, in which case Cancelled status is preserved.
246 */
247 protected void setDone() {
248 lock.lock();
249 try {
250 Object r = runner;
251 if (r == DONE || r == CANCELLED)
252 return;
253 runner = DONE;
254 }
255 finally{
256 lock.unlock();
257 }
258 done();
259 }
260
261 /**
262 * Attempts to set the state of this task to Running, succeeding
263 * only if the state is currently NOT Done, Running, or Cancelled.
264 * @return true if successful
265 */
266 protected boolean setRunning() {
267 lock.lock();
268 try {
269 if (runner != null)
270 return false;
271 runner = Thread.currentThread();
272 return true;
273 }
274 finally {
275 lock.unlock();
276 }
277 }
278
279 /**
280 * Sets this Future to the results of computation
281 */
282 public void run() {
283 if (setRunning()) {
284 try {
285 try {
286 if (runnable != null)
287 runnable.run();
288 else if (callable != null)
289 set(callable.call());
290 } catch(Throwable ex) {
291 setException(ex);
292 }
293 } finally {
294 setDone();
295 }
296 }
297 }
298
299 /**
300 * Sets this Future to the results of computation and then resets
301 * to initial state. This may be useful for tasks that intriniscally
302 * execute more than once.
303 */
304 protected void runAndReset() {
305 if (setRunning()) {
306 try {
307 try {
308 if (runnable != null)
309 runnable.run();
310 else if (callable != null)
311 set(callable.call());
312 } catch(Throwable ex) {
313 setException(ex);
314 }
315 } finally {
316 reset();
317 }
318 }
319 }
320
321 /**
322 * Protected method invoked when this task transitions to state
323 * <tt>isDone</tt> (whether normally or via cancellation). The
324 * default implementation does nothing. Subclasses may override
325 * this method to invoke completion callbacks or perform
326 * bookkeeping. Note that you can query status inside the
327 * implementation of this method to determine whether this task
328 * has been cancelled.
329 */
330 protected void done() { }
331
332 /**
333 * Resets the run state of this task to its initial state unless
334 * it has been cancelled. (Note that a cancelled task cannot be
335 * reset.)
336 * @return true if successful
337 */
338 protected boolean reset() {
339 lock.lock();
340 try {
341 if (runner == CANCELLED)
342 return false;
343 runner = null;
344 return true;
345 }
346 finally {
347 lock.unlock();
348 }
349 }
350
351 /**
352 * Return the <tt>Runnable</tt> or <tt>Callable</tt> used
353 * in the constructor for this <tt>Future</tt>.
354 * @return the task
355 */
356 protected Object getTask() {
357 if (runnable != null)
358 return runnable;
359 else
360 return callable;
361 }
362
363 }
364