ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FutureTask.java
Revision: 1.14
Committed: Thu Dec 4 21:39:09 2003 UTC (20 years, 6 months ago) by dl
Branch: MAIN
Changes since 1.13: +116 -102 lines
Log Message:
documentation touch-ups

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 final Runnable runnable;
62 /** The callable, if non-null, then runnable is null */
63 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 * <tt>Boolean.TRUE</tt>.
96 * @throws NullPointerException if runnable is null
97 */
98 public FutureTask(final Runnable runnable, final V result) {
99 if (runnable == null)
100 throw new NullPointerException();
101 this.runnable = runnable;
102 this.result = result;
103 this.callable = null;
104 }
105
106 public boolean cancel(boolean mayInterruptIfRunning) {
107 lock.lock();
108 try {
109 Object r = runner;
110 if (r == DONE || r == CANCELLED)
111 return false;
112 if (mayInterruptIfRunning && r != null && r instanceof Thread)
113 ((Thread)r).interrupt();
114 runner = CANCELLED;
115 }
116 finally{
117 lock.unlock();
118 }
119 done();
120 return true;
121 }
122
123 public boolean isCancelled() {
124 return runner == CANCELLED;
125 }
126
127 public boolean isDone() {
128 Object r = runner;
129 return r == DONE || r == CANCELLED;
130 }
131
132 /**
133 * Waits if necessary for the call to <tt>callable.call</tt> to
134 * complete, and then retrieves its result.
135 *
136 * @return computed result
137 * @throws CancellationException if underlying computation was
138 * cancelled
139 * @throws ExecutionException if underlying computation threw an
140 * exception
141 * @throws InterruptedException if current thread was interrupted
142 * while waiting
143 */
144 public V get() throws InterruptedException, ExecutionException {
145 lock.lock();
146 try {
147 while (!isDone())
148 accessible.await();
149 if (isCancelled())
150 throw new CancellationException();
151 else if (exception != null)
152 throw new ExecutionException(exception);
153 else
154 return result;
155 } finally {
156 lock.unlock();
157 }
158 }
159
160 /**
161 * Waits if necessary for at most the given time for the call to
162 * <tt>callable.call</tt> to complete, and then retrieves its
163 * result.
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 * Protected method invoked when this task transitions to state
301 * <tt>isDone</tt> (whether normally or via cancellation). The
302 * default implementation does nothing. Subclasses may override
303 * this method to invoke completion callbacks or perform
304 * bookkeeping. Note that you can query status inside the
305 * implementation of this method to determine whether this task
306 * has been cancelled.
307 */
308 protected void done() { }
309
310 /**
311 * Resets the run state of this task to its initial state unless
312 * it has been cancelled. (Note that a cancelled task cannot be
313 * reset.)
314 * @return true if successful
315 */
316 protected boolean reset() {
317 lock.lock();
318 try {
319 if (runner == CANCELLED)
320 return false;
321 runner = null;
322 return true;
323 }
324 finally {
325 lock.unlock();
326 }
327 }
328 }
329
330
331
332
333
334
335
336
337
338