ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FutureTask.java
Revision: 1.22
Committed: Sat Dec 27 17:19:03 2003 UTC (20 years, 5 months ago) by dl
Branch: MAIN
Changes since 1.21: +1 -1 lines
Log Message:
Adapt to AbstractQueuedSynchronizer

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 "runState" indicating task is cancelled
37 */
38 private static final Object CANCELLED = new Object();
39
40 /**
41 * Special value for "runState" 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 runState;
53
54 /** The underlying callable */
55 private final Callable<V> callable;
56 /** The result to return from get() */
57 private V result;
58 /** The exception to throw from get() */
59 private Throwable exception;
60
61 private final ReentrantLock lock = new ReentrantLock();
62 private final Condition accessible = lock.newCondition();
63
64 /**
65 * Constructs a <tt>FutureTask</tt> that will upon running, execute the
66 * given <tt>Callable</tt>.
67 *
68 * @param callable the callable task
69 * @throws NullPointerException if callable is null
70 */
71 public FutureTask(Callable<V> callable) {
72 if (callable == null)
73 throw new NullPointerException();
74 this.callable = callable;
75 }
76
77 /**
78 * Constructs a <tt>FutureTask</tt> that will upon running, execute the
79 * given <tt>Runnable</tt>, and arrange that <tt>get</tt> will return the
80 * given result on successful completion.
81 *
82 * @param runnable the runnable task
83 * @param result the result to return on successful completion. If
84 * you don't need a particular result, consider using
85 * constructions of the form:
86 * <tt>Future&lt;?&gt; f = new FutureTask&lt;Object&gt;(runnable, null)</tt>
87 * @throws NullPointerException if runnable is null
88 */
89 public FutureTask(Runnable runnable, V result) {
90 this.callable = Executors.callable(runnable, result);
91 }
92
93 public boolean isCancelled() {
94 return runState == CANCELLED;
95 }
96
97 public boolean isDone() {
98 Object r = runState;
99 return r == DONE || r == CANCELLED;
100 }
101
102 public boolean cancel(boolean mayInterruptIfRunning) {
103 final ReentrantLock lock = this.lock;
104 Thread interruptThread = null;
105 lock.lock();
106 try {
107 Object r = runState;
108 if (r == DONE || r == CANCELLED)
109 return false;
110 if (mayInterruptIfRunning && r != null && r instanceof Thread)
111 interruptThread = (Thread)r;
112 accessible.signalAll();
113 runState = CANCELLED;
114 }
115 finally{
116 lock.unlock();
117 }
118 if (interruptThread != null)
119 interruptThread.interrupt();
120 done();
121 return true;
122 }
123
124 /**
125 * Waits if necessary for execution to complete, and then
126 * retrieves its result.
127 *
128 * @return computed result
129 * @throws CancellationException if underlying computation was
130 * cancelled
131 * @throws ExecutionException if underlying computation threw an
132 * exception
133 * @throws InterruptedException if current thread was interrupted
134 * while waiting
135 */
136 public V get() throws InterruptedException, ExecutionException {
137 final ReentrantLock lock = this.lock;
138 lock.lock();
139 try {
140 for (;;) {
141 Object r = runState;
142 if (r == CANCELLED)
143 throw new CancellationException();
144 if (r == DONE) {
145 if (exception != null)
146 throw new ExecutionException(exception);
147 else
148 return result;
149 }
150 accessible.await();
151 }
152 } finally {
153 lock.unlock();
154 }
155 }
156
157 /**
158 * Waits if necessary for at most the given time for execution to
159 * complete, and then retrieves its result, if available.
160 *
161 * @param timeout the maximum time to wait
162 * @param unit the time unit of the timeout argument
163 * @return computed result
164 * @throws CancellationException if underlying computation was
165 * cancelled
166 * @throws ExecutionException if underlying computation threw an
167 * exception
168 * @throws InterruptedException if current thread was interrupted
169 * while waiting
170 * @throws TimeoutException if the wait timed out
171 */
172 public V get(long timeout, TimeUnit unit)
173 throws InterruptedException, ExecutionException, TimeoutException {
174 long nanos = unit.toNanos(timeout);
175 final ReentrantLock lock = this.lock;
176 lock.lock();
177 try {
178 for (;;) {
179 Object r = runState;
180 if (r == CANCELLED)
181 throw new CancellationException();
182 if (r == DONE) {
183 if (exception != null)
184 throw new ExecutionException(exception);
185 else
186 return result;
187 }
188 if (nanos <= 0)
189 throw new TimeoutException();
190 nanos = accessible.awaitNanos(nanos);
191 }
192 } finally {
193 lock.unlock();
194 }
195 }
196
197 /**
198 * Protected method invoked when this task transitions to state
199 * <tt>isDone</tt> (whether normally or via cancellation). The
200 * default implementation does nothing. Subclasses may override
201 * this method to invoke completion callbacks or perform
202 * bookkeeping. Note that you can query status inside the
203 * implementation of this method to determine whether this task
204 * has been cancelled.
205 */
206 protected void done() { }
207
208 /**
209 * Sets the result of this Future to the given value unless
210 * this future has been cancelled
211 * @param v the value
212 */
213 protected void set(V v) {
214 final ReentrantLock lock = this.lock;
215 lock.lock();
216 try {
217 if (runState == CANCELLED)
218 return;
219 result = v;
220 accessible.signalAll();
221 runState = DONE;
222 } finally {
223 lock.unlock();
224 }
225 done();
226 }
227
228 /**
229 * Causes this future to report an <tt>ExecutionException</tt>
230 * with the given throwable as its cause, unless this Future has
231 * been cancelled.
232 * @param t the cause of failure.
233 */
234 protected void setException(Throwable t) {
235 final ReentrantLock lock = this.lock;
236 lock.lock();
237 try {
238 if (runState == CANCELLED)
239 return;
240 exception = t;
241 accessible.signalAll();
242 runState = DONE;
243 } finally {
244 lock.unlock();
245 }
246 done();
247 }
248
249 /**
250 * Attempts to set the state of this task to Running, succeeding
251 * only if the state is currently NOT Done, Running, or Cancelled.
252 * @return true if successful
253 */
254 private boolean setRunning() {
255 final ReentrantLock lock = this.lock;
256 lock.lock();
257 try {
258 if (runState != null)
259 return false;
260 runState = Thread.currentThread();
261 return true;
262 }
263 finally {
264 lock.unlock();
265 }
266 }
267
268 /**
269 * Resets the run state of this task to its initial state unless
270 * it has been cancelled. (Note that a cancelled task cannot be
271 * reset.)
272 * @return true if successful
273 */
274 private boolean reset() {
275 final ReentrantLock lock = this.lock;
276 lock.lock();
277 try {
278 if (runState == CANCELLED)
279 return false;
280 runState = null;
281 return true;
282 }
283 finally {
284 lock.unlock();
285 }
286 }
287
288 /**
289 * Sets this Future to the result of computation unless
290 * it has been cancelled.
291 */
292 public void run() {
293 if (setRunning()) {
294 try {
295 set(callable.call());
296 } catch(Throwable ex) {
297 setException(ex);
298 }
299 }
300 }
301
302 /**
303 * Executes the computation and then resets this Future to initial
304 * state; failing to do so if the computation encounters an
305 * exception or is cancelled. This is designed for use with tasks
306 * that intrinsically execute more than once.
307 * @return true if successfully run and reset
308 */
309 protected boolean runAndReset() {
310 if (setRunning()) {
311 try {
312 // don't bother to set result; it can't be accessed
313 callable.call();
314 return reset();
315 } catch(Throwable ex) {
316 setException(ex);
317 }
318 }
319 return false;
320 }
321
322 }
323