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

# 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
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 private final ReentrantLock lock = new ReentrantLock();
46 private final Condition accessible = lock.newCondition();
47
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 lock.lock();
91 try {
92 if (ready || runner != null)
93 return;
94 runner = Thread.currentThread();
95 }
96 finally {
97 lock.unlock();
98 }
99 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 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 }
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 * @param unit the time unit of the timeout argument
141 * @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 public V get(long timeout, TimeUnit unit)
149 throws InterruptedException, ExecutionException, TimeoutException {
150
151 lock.lock();
152 try {
153 if (!ready) {
154 long nanos = unit.toNanos(timeout);
155 do {
156 if (nanos <= 0)
157 throw new TimeoutException();
158 nanos = accessible.awaitNanos(nanos);
159 } while (!ready);
160 }
161 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 }
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 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 }
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 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 }
215
216 /* Cancellable implementation. */
217
218 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 }
232
233 public boolean isCancelled() {
234 lock.lock();
235 try {
236 return cancelled;
237 }
238 finally {
239 lock.unlock();
240 }
241 }
242
243 public boolean isDone() {
244 lock.lock();
245 try {
246 return ready;
247 }
248 finally {
249 lock.unlock();
250 }
251 }
252 }
253
254
255
256
257
258
259
260
261
262