ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FutureTask.java
Revision: 1.26
Committed: Wed Jan 7 01:00:50 2004 UTC (20 years, 5 months ago) by dl
Branch: MAIN
Changes since 1.25: +2 -2 lines
Log Message:
replace isFirst param with isFirst method

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, as explained at
4 * http://creativecommons.org/licenses/publicdomain
5 */
6
7 package java.util.concurrent;
8 import java.util.concurrent.locks.*;
9
10 /**
11 * A cancellable asynchronous computation. This class provides a base
12 * implementation of {@link Future}, with methods to start and cancel
13 * a computation, query to see if the computation is complete, and
14 * retrieve the result of the computation. The result can only be
15 * retrieved when the computation has completed; the <tt>get</tt>
16 * method will block if the computation has not yet completed. Once
17 * the computation has completed, the computation cannot be restarted
18 * or cancelled.
19 *
20 * <p>A <tt>FutureTask</tt> can be used to wrap a {@link Callable} or
21 * {@link java.lang.Runnable} object. Because <tt>FutureTask</tt>
22 * implements <tt>Runnable</tt>, a <tt>FutureTask</tt> can be
23 * submitted to an {@link Executor} for execution.
24 *
25 * <p>In addition to serving as a standalone class, this class provides
26 * <tt>protected</tt> functionality that may be useful when creating
27 * customized task classes.
28 *
29 * @since 1.5
30 * @author Doug Lea
31 * @param <V> The result type returned by this FutureTask's <tt>get</tt> method
32 */
33 public class FutureTask<V> implements Future<V>, Runnable {
34 /** Synchronization control for FutureTask */
35 private final Sync sync;
36
37 /**
38 * Constructs a <tt>FutureTask</tt> that will upon running, execute the
39 * given <tt>Callable</tt>.
40 *
41 * @param callable the callable task
42 * @throws NullPointerException if callable is null
43 */
44 public FutureTask(Callable<V> callable) {
45 if (callable == null)
46 throw new NullPointerException();
47 sync = new Sync(callable);
48 }
49
50 /**
51 * Constructs a <tt>FutureTask</tt> that will upon running, execute the
52 * given <tt>Runnable</tt>, and arrange that <tt>get</tt> will return the
53 * given result on successful completion.
54 *
55 * @param runnable the runnable task
56 * @param result the result to return on successful completion. If
57 * you don't need a particular result, consider using
58 * constructions of the form:
59 * <tt>Future&lt;?&gt; f = new FutureTask&lt;Object&gt;(runnable, null)</tt>
60 * @throws NullPointerException if runnable is null
61 */
62 public FutureTask(Runnable runnable, V result) {
63 sync = new Sync(Executors.callable(runnable, result));
64 }
65
66 public boolean isCancelled() {
67 return sync.doIsCancelled();
68 }
69
70 public boolean isDone() {
71 return sync.doIsDone();
72 }
73
74 public boolean cancel(boolean mayInterruptIfRunning) {
75 return sync.doCancel(mayInterruptIfRunning);
76 }
77
78 /**
79 * Waits if necessary for execution to complete, and then
80 * retrieves its result.
81 *
82 * @return computed result
83 * @throws CancellationException if underlying computation was
84 * cancelled
85 * @throws ExecutionException if underlying computation threw an
86 * exception
87 * @throws InterruptedException if current thread was interrupted
88 * while waiting
89 */
90 public V get() throws InterruptedException, ExecutionException {
91 return sync.doGet();
92 }
93
94 /**
95 * Waits if necessary for at most the given time for execution to
96 * complete, and then retrieves its result, if available.
97 *
98 * @param timeout the maximum time to wait
99 * @param unit the time unit of the timeout argument
100 * @return computed result
101 * @throws CancellationException if underlying computation was
102 * cancelled
103 * @throws ExecutionException if underlying computation threw an
104 * exception
105 * @throws InterruptedException if current thread was interrupted
106 * while waiting
107 * @throws TimeoutException if the wait timed out
108 */
109 public V get(long timeout, TimeUnit unit)
110 throws InterruptedException, ExecutionException, TimeoutException {
111 return sync.doGet(unit.toNanos(timeout));
112 }
113
114 /**
115 * Protected method invoked when this task transitions to state
116 * <tt>isDone</tt> (whether normally or via cancellation). The
117 * default implementation does nothing. Subclasses may override
118 * this method to invoke completion callbacks or perform
119 * bookkeeping. Note that you can query status inside the
120 * implementation of this method to determine whether this task
121 * has been cancelled.
122 */
123 protected void done() { }
124
125 /**
126 * Sets the result of this Future to the given value unless
127 * this future has already been set or has been cancelled
128 * @param v the value
129 */
130 protected void set(V v) {
131 sync.doSet(v);
132 }
133
134 /**
135 * Causes this future to report an <tt>ExecutionException</tt>
136 * with the given throwable as its cause, unless this Future has
137 * already been set or has been cancelled.
138 * @param t the cause of failure.
139 */
140 protected void setException(Throwable t) {
141 sync.doSetException(t);
142 }
143
144 /**
145 * Sets this Future to the result of computation unless
146 * it has been cancelled.
147 */
148 public void run() {
149 sync.doRun();
150 }
151
152 /**
153 * Executes the computation without setting result, and then
154 * resets this Future to initial state; failing to do so if the
155 * computation encounters an exception or is cancelled. This is
156 * designed for use with tasks that intrinsically execute more
157 * than once.
158 * @return true if successfully run and reset
159 */
160 protected boolean runAndReset() {
161 return sync.doRunAndReset();
162 }
163
164 /**
165 * Synchronization control for FutureTask. Note that this must be
166 * a non-static inner class in order to invoke protected
167 * <tt>done</tt> method. For clarity, all inner class support
168 * methods are same as outer, prefixed with "do".
169 *
170 * Uses AQS sync state to represent run status
171 */
172 private final class Sync extends AbstractQueuedSynchronizer {
173 /** State value representing that task is running */
174 private static final int RUNNING = 1;
175 /** State value representing that task ran */
176 private static final int RAN = 2;
177 /** State value representing that task was cancelled */
178 private static final int CANCELLED = 4;
179
180 /** The underlying callable */
181 private final Callable<V> callable;
182 /** The result to return from get() */
183 private V result;
184 /** The exception to throw from get() */
185 private Throwable exception;
186
187 /**
188 * The thread running task. When nulled after set/cancel, this
189 * indicates that the results are accessible. Must be
190 * volatile, to serve as write barrier on completion.
191 */
192 private volatile Thread runner;
193
194 Sync(Callable<V> callable) {
195 this.callable = callable;
196 }
197
198 private boolean ranOrCancelled(int state) {
199 return (state & (RAN | CANCELLED)) != 0;
200 }
201
202 /**
203 * Implements AQS base acquire to succeed if ran or cancelled
204 */
205 protected int tryAcquireShared(int ignore) {
206 return doIsDone()? 1 : -1;
207 }
208
209 /**
210 * Implements AQS base release to always signal after setting
211 * final done status by nulling runner thread.
212 */
213 protected boolean tryReleaseShared(int ignore) {
214 runner = null;
215 return true;
216 }
217
218 boolean doIsCancelled() {
219 return getState() == CANCELLED;
220 }
221
222 boolean doIsDone() {
223 return ranOrCancelled(getState()) && runner == null;
224 }
225
226 V doGet() throws InterruptedException, ExecutionException {
227 acquireSharedInterruptibly(0);
228 if (getState() == CANCELLED)
229 throw new CancellationException();
230 if (exception != null)
231 throw new ExecutionException(exception);
232 return result;
233 }
234
235 V doGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
236 if (!acquireSharedTimed(0, nanosTimeout))
237 throw new TimeoutException();
238 if (getState() == CANCELLED)
239 throw new CancellationException();
240 if (exception != null)
241 throw new ExecutionException(exception);
242 return result;
243 }
244
245 void doSet(V v) {
246 int s = getState();
247 if (ranOrCancelled(s) || !compareAndSetState(s, RAN))
248 return;
249 result = v;
250 releaseShared(0);
251 done();
252 }
253
254 void doSetException(Throwable t) {
255 int s = getState();
256 if (ranOrCancelled(s) || !compareAndSetState(s, RAN))
257 return;
258 exception = t;
259 result = null;
260 releaseShared(0);
261 done();
262 }
263
264 boolean doCancel(boolean mayInterruptIfRunning) {
265 int s = getState();
266 if (ranOrCancelled(s) || !compareAndSetState(s, CANCELLED))
267 return false;
268 if (mayInterruptIfRunning) {
269 Thread r = runner;
270 if (r != null)
271 r.interrupt();
272 }
273 releaseShared(0);
274 done();
275 return true;
276 }
277
278 void doRun() {
279 if (!compareAndSetState(0, RUNNING))
280 return;
281 try {
282 runner = Thread.currentThread();
283 doSet(callable.call());
284 } catch(Throwable ex) {
285 doSetException(ex);
286 }
287 }
288
289 boolean doRunAndReset() {
290 if (!compareAndSetState(0, RUNNING))
291 return false;
292 try {
293 runner = Thread.currentThread();
294 callable.call(); // don't set result
295 runner = null;
296 return compareAndSetState(RUNNING, 0);
297 } catch(Throwable ex) {
298 doSetException(ex);
299 return false;
300 }
301 }
302 }
303 }