ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FutureTask.java
Revision: 1.2
Committed: Tue May 27 18:14:40 2003 UTC (21 years ago) by dl
Branch: MAIN
CVS Tags: JSR166_PRERELEASE_0_1
Changes since 1.1: +95 -52 lines
Log Message:
re-check-in initial implementations

File Contents

# User Rev Content
1 tim 1.1 /*
2 dl 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 tim 1.1 */
6    
7     package java.util.concurrent;
8    
9     /**
10     * A cancellable asynchronous computation.
11     *
12     * <p>Provides methods to start and cancel the computation, query to see if
13     * the computation is complete, and retrieve the result of the computation.
14     * The result can only be retrieved when the computation has completed;
15     * the <tt>get</tt> method will block if the computation has not yet completed.
16     * Once the computation is completed, the result cannot be changed, nor can the
17     * computation be restarted or cancelled.
18     *
19     * <p>Because <tt>FutureTask</tt> implements <tt>Runnable</tt>, a
20     * <tt>FutureTask</tt> can be submitted to an {@link Executor} for
21     * current or deferred execution.
22     *
23     * <p>A <tt>FutureTask</tt> can be used to wrap a <tt>Callable</tt> or
24     * <tt>Runnable</tt> object so that it can be scheduled for execution in a
25     * thread or an <tt>Executor</tt>, cancel
26     * computation before the computation completes, and wait for or
27     * retrieve the results. If the computation threw an exception, the
28     * exception is propagated to any thread that attempts to retrieve the
29     * result.
30     *
31     * @see Executor
32     *
33     * @since 1.5
34     * @spec JSR-166
35     * @revised $Date: 2003/03/31 03:50:08 $
36     * @editor $Author: dholmes $
37     */
38     public class FutureTask<V> implements Cancellable, Future<V>, Runnable {
39     private V result;
40     private Throwable exception;
41     private boolean ready;
42     private Thread runner;
43     private final Callable<V> callable;
44     private boolean cancelled;
45 dl 1.2 private final ReentrantLock lock = new ReentrantLock();
46     private final Condition accessible = lock.newCondition();
47 tim 1.1
48     /**
49     * Constructs a <tt>FutureTask</tt> that will upon running, execute the
50     * given <tt>Callable</tt>.
51     *
52     * @param callable the callable task
53     */
54     public FutureTask(Callable<V> callable) {
55     this.callable = callable;
56     }
57    
58     /**
59     * Constructs a <tt>FutureTask</tt> that will upon running, execute the
60     * given <tt>Runnable</tt>, and arrange that <tt>get</tt> will return the
61     * given result on successful completion.
62     *
63     * @param runnable the runnable task
64     * @param result the result to return on successful completion. If
65     * you don't need a particular result, consider just using
66     * <tt>Boolean.TRUE</tt>.
67     */
68     public FutureTask(final Runnable runnable, final V result) {
69     callable = new Callable<V>() {
70     public V call() {
71     runnable.run();
72     return result;
73     }
74     };
75     }
76    
77     /* Runnable implementation. */
78    
79     /** Starts the computation. */
80     public void run() {
81     doRun();
82     }
83    
84     /**
85     * Executes the callable if not already cancelled or running, and
86     * sets the value or exception with its results.
87     */
88     protected void doRun() {
89     try {
90 dl 1.2 lock.lock();
91     try {
92 tim 1.1 if (ready || runner != null)
93     return;
94     runner = Thread.currentThread();
95     }
96 dl 1.2 finally {
97     lock.unlock();
98     }
99 tim 1.1 set(callable.call());
100     }
101     catch(Throwable ex) {
102     setException(ex);
103     }
104     }
105    
106     /* Future implementation. INHERIT this javadoc from interface??? Note CancellationException. */
107    
108     /**
109     * Waits if necessary for the computation to complete, and then retrieves
110     * its result.
111     *
112     * @return the computed result
113     * @throws CancellationException if task producing this value was
114     * cancelled before completion
115     * @throws ExecutionException if the underlying computation threw an exception
116     * @throws InterruptedException if current thread was interrupted while waiting
117     */
118 dl 1.2 public V get() throws InterruptedException, ExecutionException {
119     lock.lock();
120     try {
121     while (!ready)
122     accessible.await();
123     if (cancelled)
124     throw new CancellationException();
125     else if (exception != null)
126     throw new ExecutionException(exception);
127     else
128     return result;
129     }
130     finally {
131     lock.unlock();
132     }
133 tim 1.1 }
134    
135     /**
136     * Waits if necessary for at most the given time for the computation to
137     * complete, and then retrieves its result.
138     *
139     * @param timeout the maximum time to wait
140 dl 1.2 * @param unit the time unit of the timeout argument
141 tim 1.1 * @return value of this task
142     * @throws CancellationException if task producing this value was cancelled before completion
143     * @throws ExecutionException if the underlying computation
144     * threw an exception.
145     * @throws InterruptedException if current thread was interrupted while waiting
146     * @throws TimeoutException if the wait timed out
147     */
148 dl 1.2 public V get(long timeout, TimeUnit unit)
149 tim 1.1 throws InterruptedException, ExecutionException, TimeoutException {
150    
151 dl 1.2 lock.lock();
152     try {
153     if (!ready) {
154     long nanos = unit.toNanos(timeout);
155     do {
156     if (nanos <= 0)
157 tim 1.1 throw new TimeoutException();
158 dl 1.2 nanos = accessible.awaitNanos(nanos);
159     } while (!ready);
160 tim 1.1 }
161 dl 1.2 if (cancelled)
162     throw new CancellationException();
163     else if (exception != null)
164     throw new ExecutionException(exception);
165     else
166     return result;
167     }
168     finally {
169     lock.unlock();
170 tim 1.1 }
171     }
172    
173     /**
174     * Sets the value of this task to the given value. This method
175     * should only be called once; once it is called, the computation
176     * is assumed to have completed.
177     *
178     * @param v the value
179     *
180     * @fixme Need to clarify "should" in "should only be called once".
181     */
182 dl 1.2 protected void set(V v) {
183     lock.lock();
184     try {
185     ready = true;
186     result = v;
187     runner = null;
188     accessible.signalAll();
189     }
190     finally {
191     lock.unlock();
192     }
193 tim 1.1 }
194    
195     /**
196     * Indicates that the computation has failed. After this method
197     * is called, the computation is assumed to be completed, and any
198     * attempt to retrieve the result will throw an <tt>ExecutionException</tt>
199     * wrapping the exception provided here.
200     *
201     * @param t the throwable
202     */
203 dl 1.2 protected void setException(Throwable t) {
204     lock.lock();
205     try {
206     ready = true;
207     exception = t;
208     runner = null;
209     accessible.signalAll();
210     }
211     finally {
212     lock.unlock();
213     }
214 tim 1.1 }
215    
216     /* Cancellable implementation. */
217    
218 dl 1.2 public boolean cancel(boolean mayInterruptIfRunning) {
219     lock.lock();
220     try {
221     if (ready || cancelled)
222     return false;
223     if (mayInterruptIfRunning &&
224     runner != null && runner != Thread.currentThread())
225     runner.interrupt();
226     return cancelled = ready = true;
227     }
228     finally {
229     lock.unlock();
230     }
231 tim 1.1 }
232    
233 dl 1.2 public boolean isCancelled() {
234     lock.lock();
235     try {
236     return cancelled;
237     }
238     finally {
239     lock.unlock();
240     }
241 tim 1.1 }
242    
243 dl 1.2 public boolean isDone() {
244     lock.lock();
245     try {
246     return ready;
247     }
248     finally {
249     lock.unlock();
250     }
251 tim 1.1 }
252     }
253    
254    
255    
256    
257    
258    
259    
260    
261    
262