ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FutureTask.java
(Generate patch)

Comparing jsr166/src/main/java/util/concurrent/FutureTask.java (file contents):
Revision 1.12 by dl, Mon Nov 10 17:31:23 2003 UTC vs.
Revision 1.13 by dl, Thu Dec 4 20:54:29 2003 UTC

# Line 5 | Line 5
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
# Line 25 | Line 27 | package java.util.concurrent;
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> extends CancellableTask implements Future<V> {
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 <     * Callable created in FutureTask(runnable, result) constructor
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 <    private static class RunnableAsCallable<V> implements Callable<V> {
49 <        private final Runnable runnable;
50 <        private final V result;
51 <        RunnableAsCallable(Runnable runnable, V result) {
52 <            this.runnable = runnable;
53 <            this.result = result;
54 <        }
55 <        public V call() {
41 <            runnable.run();
42 <            return result;
43 <        }
44 <    }
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
# Line 51 | Line 62 | public class FutureTask<V> extends Cance
62       * @throws NullPointerException if callable is null
63       */
64      public FutureTask(Callable<V> callable) {
54        // must set after super ctor call to use inner class
55        super();
65          if (callable == null)
66              throw new NullPointerException();
67 <        setRunnable(new InnerCancellableFuture<V>(callable));
67 >        this.callable = callable;
68 >        this.runnable = null;
69      }
70  
71      /**
# Line 70 | Line 80 | public class FutureTask<V> extends Cance
80       * @throws NullPointerException if runnable is null
81       */
82      public FutureTask(final Runnable runnable, final V result) {
73        super();
83          if (runnable == null)
84              throw new NullPointerException();
85 <        setRunnable(new InnerCancellableFuture<V>
86 <                    (new RunnableAsCallable<V>(runnable, result)));
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 <     * Waits if necessary for the computation to complete, and then retrieves
118 <     * its result.
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 the computed result
220 <     * @throws CancellationException if task producing this value was
221 <     * cancelled before completion
222 <     * @throws ExecutionException if the underlying computation threw
223 <     * an exception
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 <        return ((InnerCancellableFuture<V>)getRunnable()).get();
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 computation to
245 <     * complete, and then retrieves its result.
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 value of this task
251 <     * @throws CancellationException if task producing this value was
252 <     * cancelled before completion
253 <     * @throws ExecutionException if the underlying computation threw
254 <     * an exception.
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 <        return ((InnerCancellableFuture<V>)getRunnable()).get(timeout, unit);
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 value of this task to the given value.  After this
118 <     * method is called, the computation is assumed to be completed --
119 <     * threads already waiting for the result via <tt>get</tt> are
120 <     * unblocked, and future attempts to retrieve the result will not
121 <     * block. While not explicitly disallowed, it is rarely a good idea
122 <     * to invoke <tt>set</tt> more than once.
123 <     *
283 >     * Sets the result of this Future to the given value.
284       * @param v the value
285 <     *
126 <     */
285 >     */
286      protected void set(V v) {
287 <        ((InnerCancellableFuture<V>)getRunnable()).set(v);
287 >        lock.lock();
288 >        try {
289 >            result = v;
290 >            setDone();
291 >            accessible.signalAll();
292 >        } finally {
293 >            lock.unlock();
294 >        }
295      }
296  
297      /**
298 <     * Indicates that the computation has failed.  After this method
299 <     * is called, the computation is assumed to be completed, and any
300 <     * attempt to retrieve the result will throw an <tt>ExecutionException</tt>
301 <     * wrapping the exception provided here.
136 <     *
137 <     * @param t the throwable
138 <     */
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 <        ((InnerCancellableFuture<V>)getRunnable()).setException(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  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines