ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FutureTask.java
Revision: 1.19
Committed: Mon Dec 22 00:48:14 2003 UTC (20 years, 5 months ago) by dl
Branch: MAIN
Changes since 1.18: +20 -29 lines
Log Message:
Streamline status settting

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 runner = CANCELLED;
114 if (mayInterruptIfRunning && r != null && r instanceof Thread)
115 ((Thread)r).interrupt();
116 // propagate to nested future
117 Runnable subtask = runnable;
118 if (subtask != null && subtask instanceof Future)
119 ((Future<?>)subtask).cancel(false);
120 }
121 finally{
122 lock.unlock();
123 }
124 done();
125 return true;
126 }
127
128 public boolean isCancelled() {
129 return runner == CANCELLED;
130 }
131
132 public boolean isDone() {
133 Object r = runner;
134 return r == DONE || r == CANCELLED;
135 }
136
137 /**
138 * Waits if necessary for execution to complete, and then
139 * retrieves its result.
140 *
141 * @return computed result
142 * @throws CancellationException if underlying computation was
143 * cancelled
144 * @throws ExecutionException if underlying computation threw an
145 * exception
146 * @throws InterruptedException if current thread was interrupted
147 * while waiting
148 */
149 public V get() throws InterruptedException, ExecutionException {
150 lock.lock();
151 try {
152 while (!isDone())
153 accessible.await();
154 if (isCancelled())
155 throw new CancellationException();
156 else if (exception != null)
157 throw new ExecutionException(exception);
158 else
159 return result;
160 } finally {
161 lock.unlock();
162 }
163 }
164
165 /**
166 * Waits if necessary for at most the given time for execution to
167 * complete, and then retrieves its result, if available.
168 *
169 * @param timeout the maximum time to wait
170 * @param unit the time unit of the timeout argument
171 * @return computed result
172 * @throws CancellationException if underlying computation was
173 * cancelled
174 * @throws ExecutionException if underlying computation threw an
175 * exception
176 * @throws InterruptedException if current thread was interrupted
177 * while waiting
178 * @throws TimeoutException if the wait timed out
179 */
180 public V get(long timeout, TimeUnit unit)
181 throws InterruptedException, ExecutionException, TimeoutException {
182 lock.lock();
183 try {
184 if (!isDone()) {
185 long nanos = unit.toNanos(timeout);
186 do {
187 if (nanos <= 0)
188 throw new TimeoutException();
189 nanos = accessible.awaitNanos(nanos);
190 } while (!isDone());
191 }
192 if (isCancelled())
193 throw new CancellationException();
194 else if (exception != null)
195 throw new ExecutionException(exception);
196 else
197 return result;
198 } finally {
199 lock.unlock();
200 }
201 }
202
203 /**
204 * Sets the result of this Future to the given value.
205 * @param v the value
206 */
207 protected void set(V v) {
208 lock.lock();
209 try {
210 result = v;
211 setDone();
212 } finally {
213 lock.unlock();
214 }
215 }
216
217 /**
218 * Causes this future to report an <tt>ExecutionException</tt>
219 * with the given throwable as its cause.
220 * @param t the cause of failure.
221 */
222 protected void setException(Throwable t) {
223 lock.lock();
224 try {
225 exception = t;
226 setDone();
227 } finally {
228 lock.unlock();
229 }
230 }
231
232 /**
233 * Sets the state of this task to Cancelled.
234 */
235 protected void setCancelled() {
236 lock.lock();
237 try {
238 runner = CANCELLED;
239 }
240 finally{
241 lock.unlock();
242 }
243 }
244
245 /**
246 * Sets the state of this task to Done, unless already in a
247 * Cancelled state, in which case Cancelled status is preserved.
248 * Called only while lock held
249 */
250 private void setDone() {
251 Object r = runner;
252 if (r != CANCELLED)
253 runner = DONE;
254 accessible.signalAll();
255 }
256
257 /**
258 * Attempts to set the state of this task to Running, succeeding
259 * only if the state is currently NOT Done, Running, or Cancelled.
260 * @return true if successful
261 */
262 protected boolean setRunning() {
263 lock.lock();
264 try {
265 if (runner != null)
266 return false;
267 runner = Thread.currentThread();
268 return true;
269 }
270 finally {
271 lock.unlock();
272 }
273 }
274
275 /**
276 * Sets this Future to the results of computation
277 */
278 public void run() {
279 if (setRunning()) {
280 try {
281 if (runnable != null) {
282 runnable.run();
283 set(result);
284 }
285 else if (callable != null)
286 set(callable.call());
287 } catch(Throwable ex) {
288 setException(ex);
289 }
290 done();
291 }
292 }
293
294 /**
295 * Sets this Future to the results of computation and then resets
296 * to initial state. This may be useful for tasks that intriniscally
297 * execute more than once.
298 */
299 protected void runAndReset() {
300 if (setRunning()) {
301 try {
302 if (runnable != null) {
303 runnable.run();
304 set(result);
305 }
306 else if (callable != null)
307 set(callable.call());
308 } catch(Throwable ex) {
309 setException(ex);
310 } finally {
311 reset();
312 }
313 }
314 }
315
316 /**
317 * Protected method invoked when this task transitions to state
318 * <tt>isDone</tt> (whether normally or via cancellation). The
319 * default implementation does nothing. Subclasses may override
320 * this method to invoke completion callbacks or perform
321 * bookkeeping. Note that you can query status inside the
322 * implementation of this method to determine whether this task
323 * has been cancelled.
324 */
325 protected void done() { }
326
327 /**
328 * Resets the run state of this task to its initial state unless
329 * it has been cancelled. (Note that a cancelled task cannot be
330 * reset.)
331 * @return true if successful
332 */
333 protected boolean reset() {
334 lock.lock();
335 try {
336 if (runner == CANCELLED)
337 return false;
338 runner = null;
339 return true;
340 }
341 finally {
342 lock.unlock();
343 }
344 }
345
346 /**
347 * Return the <tt>Runnable</tt> or <tt>Callable</tt> used
348 * in the constructor for this <tt>Future</tt>.
349 * @return the task
350 */
351 protected Object getTask() {
352 if (runnable != null)
353 return runnable;
354 else
355 return callable;
356 }
357
358 }
359