ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FutureTask.java
Revision: 1.20
Committed: Mon Dec 22 16:25:20 2003 UTC (20 years, 5 months ago) by dl
Branch: MAIN
Changes since 1.19: +99 -145 lines
Log Message:
Simplify FutureTask and AbstractExecutorService internals; improve docs

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