ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FutureTask.java
Revision: 1.13
Committed: Thu Dec 4 20:54:29 2003 UTC (20 years, 6 months ago) by dl
Branch: MAIN
Changes since 1.12: +225 -54 lines
Log Message:
Revised tests for revised Future classes

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