KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > util > concurrent > FutureTask


1 /*
2  * @(#)FutureTask.java 1.7 04/04/15
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.util.concurrent;
9 import java.util.concurrent.locks.*;
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 JavaDoc<V>, Runnable JavaDoc {
35     /** Synchronization control for FutureTask */
36     private final Sync sync;
37
38     /**
39      * Creates a <tt>FutureTask</tt> that will upon running, execute the
40      * given <tt>Callable</tt>.
41      *
42      * @param callable the callable task
43      * @throws NullPointerException if callable is null
44      */

45     public FutureTask(Callable JavaDoc<V> callable) {
46         if (callable == null)
47             throw new NullPointerException JavaDoc();
48         sync = new Sync(callable);
49     }
50
51     /**
52      * Creates a <tt>FutureTask</tt> that will upon running, execute the
53      * given <tt>Runnable</tt>, and arrange that <tt>get</tt> will return the
54      * given result on successful completion.
55      *
56      * @param runnable the runnable task
57      * @param result the result to return on successful completion. If
58      * you don't need a particular result, consider using
59      * constructions of the form:
60      * <tt>Future&lt;?&gt; f = new FutureTask&lt;Object&gt;(runnable, null)</tt>
61      * @throws NullPointerException if runnable is null
62      */

63     public FutureTask(Runnable JavaDoc runnable, V result) {
64         sync = new Sync(Executors.callable(runnable, result));
65     }
66
67     public boolean isCancelled() {
68         return sync.innerIsCancelled();
69     }
70     
71     public boolean isDone() {
72         return sync.innerIsDone();
73     }
74
75     public boolean cancel(boolean mayInterruptIfRunning) {
76         return sync.innerCancel(mayInterruptIfRunning);
77     }
78     
79     public V get() throws InterruptedException JavaDoc, ExecutionException JavaDoc {
80         return sync.innerGet();
81     }
82
83     public V get(long timeout, TimeUnit JavaDoc unit)
84         throws InterruptedException JavaDoc, ExecutionException JavaDoc, TimeoutException JavaDoc {
85         return sync.innerGet(unit.toNanos(timeout));
86     }
87
88     /**
89      * Protected method invoked when this task transitions to state
90      * <tt>isDone</tt> (whether normally or via cancellation). The
91      * default implementation does nothing. Subclasses may override
92      * this method to invoke completion callbacks or perform
93      * bookkeeping. Note that you can query status inside the
94      * implementation of this method to determine whether this task
95      * has been cancelled.
96      */

97     protected void done() { }
98
99     /**
100      * Sets the result of this Future to the given value unless
101      * this future has already been set or has been cancelled.
102      * @param v the value
103      */

104     protected void set(V v) {
105         sync.innerSet(v);
106     }
107
108     /**
109      * Causes this future to report an <tt>ExecutionException</tt>
110      * with the given throwable as its cause, unless this Future has
111      * already been set or has been cancelled.
112      * @param t the cause of failure.
113      */

114     protected void setException(Throwable JavaDoc t) {
115         sync.innerSetException(t);
116     }
117     
118     /**
119      * Sets this Future to the result of computation unless
120      * it has been cancelled.
121      */

122     public void run() {
123         sync.innerRun();
124     }
125
126     /**
127      * Executes the computation without setting its result, and then
128      * resets this Future to initial state, failing to do so if the
129      * computation encounters an exception or is cancelled. This is
130      * designed for use with tasks that intrinsically execute more
131      * than once.
132      * @return true if successfully run and reset
133      */

134     protected boolean runAndReset() {
135         return sync.innerRunAndReset();
136     }
137
138     /**
139      * Synchronization control for FutureTask. Note that this must be
140      * a non-static inner class in order to invoke the protected
141      * <tt>done</tt> method. For clarity, all inner class support
142      * methods are same as outer, prefixed with "inner".
143      *
144      * Uses AQS sync state to represent run status
145      */

146     private final class Sync extends AbstractQueuedSynchronizer {
147         /** State value representing that task is running */
148         private static final int RUNNING = 1;
149         /** State value representing that task ran */
150         private static final int RAN = 2;
151         /** State value representing that task was cancelled */
152         private static final int CANCELLED = 4;
153
154         /** The underlying callable */
155         private final Callable JavaDoc<V> callable;
156         /** The result to return from get() */
157         private V result;
158         /** The exception to throw from get() */
159         private Throwable JavaDoc exception;
160
161         /**
162          * The thread running task. When nulled after set/cancel, this
163          * indicates that the results are accessible. Must be
164          * volatile, to ensure visibility upon completion.
165          */

166         private volatile Thread JavaDoc runner;
167
168         Sync(Callable JavaDoc<V> callable) {
169             this.callable = callable;
170         }
171
172         private boolean ranOrCancelled(int state) {
173             return (state & (RAN | CANCELLED)) != 0;
174         }
175
176         /**
177          * Implements AQS base acquire to succeed if ran or cancelled
178          */

179         protected int tryAcquireShared(int ignore) {
180             return innerIsDone()? 1 : -1;
181         }
182
183         /**
184          * Implements AQS base release to always signal after setting
185          * final done status by nulling runner thread.
186          */

187         protected boolean tryReleaseShared(int ignore) {
188             runner = null;
189             return true;
190         }
191
192         boolean innerIsCancelled() {
193             return getState() == CANCELLED;
194         }
195         
196         boolean innerIsDone() {
197             return ranOrCancelled(getState()) && runner == null;
198         }
199
200         V innerGet() throws InterruptedException JavaDoc, ExecutionException JavaDoc {
201             acquireSharedInterruptibly(0);
202             if (getState() == CANCELLED)
203                 throw new CancellationException JavaDoc();
204             if (exception != null)
205                 throw new ExecutionException JavaDoc(exception);
206             return result;
207         }
208
209         V innerGet(long nanosTimeout) throws InterruptedException JavaDoc, ExecutionException JavaDoc, TimeoutException JavaDoc {
210             if (!tryAcquireSharedNanos(0, nanosTimeout))
211                 throw new TimeoutException JavaDoc();
212             if (getState() == CANCELLED)
213                 throw new CancellationException JavaDoc();
214             if (exception != null)
215                 throw new ExecutionException JavaDoc(exception);
216             return result;
217         }
218
219         void innerSet(V v) {
220         for (;;) {
221         int s = getState();
222         if (ranOrCancelled(s))
223             return;
224         if (compareAndSetState(s, RAN))
225             break;
226         }
227             result = v;
228             releaseShared(0);
229             done();
230         }
231
232         void innerSetException(Throwable JavaDoc t) {
233         for (;;) {
234         int s = getState();
235         if (ranOrCancelled(s))
236             return;
237         if (compareAndSetState(s, RAN))
238             break;
239         }
240             exception = t;
241             result = null;
242             releaseShared(0);
243             done();
244         }
245
246         boolean innerCancel(boolean mayInterruptIfRunning) {
247         for (;;) {
248         int s = getState();
249         if (ranOrCancelled(s))
250             return false;
251         if (compareAndSetState(s, CANCELLED))
252             break;
253         }
254             if (mayInterruptIfRunning) {
255                 Thread JavaDoc r = runner;
256                 if (r != null)
257                     r.interrupt();
258             }
259             releaseShared(0);
260             done();
261             return true;
262         }
263
264         void innerRun() {
265             if (!compareAndSetState(0, RUNNING))
266                 return;
267             try {
268                 runner = Thread.currentThread();
269                 innerSet(callable.call());
270             } catch(Throwable JavaDoc ex) {
271                 innerSetException(ex);
272             }
273         }
274
275         boolean innerRunAndReset() {
276             if (!compareAndSetState(0, RUNNING))
277                 return false;
278             try {
279                 runner = Thread.currentThread();
280                 callable.call(); // don't set result
281
runner = null;
282                 return compareAndSetState(RUNNING, 0);
283             } catch(Throwable JavaDoc ex) {
284                 innerSetException(ex);
285                 return false;
286             }
287         }
288     }
289 }
290
Popular Tags