ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CancellableTask.java
Revision: 1.20
Committed: Sat Oct 11 15:37:31 2003 UTC (20 years, 7 months ago) by dl
Branch: MAIN
Changes since 1.19: +1 -1 lines
Log Message:
Redeclare some Conditions as ReentrantLock.ConditionObjects

File Contents

# User Rev Content
1 dl 1.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     import java.util.concurrent.atomic.*;
9 dl 1.6 import java.util.concurrent.locks.*;
10 dl 1.1
11     /**
12 dl 1.14 * Base class for {@link Cancellable} {@link java.lang.Runnable}
13     * actions within the {@link Executor} framework. In addition to
14     * serving as a standalone class, this provides <tt>protected</tt>
15     * functionality that may be useful when creating customized task
16     * classes.
17 dl 1.5 * @since 1.5
18     * @author Doug Lea
19 dl 1.1 */
20    
21     public class CancellableTask implements Cancellable, Runnable {
22     /**
23     * Holds the run-state, taking on values:
24     * null = not yet started,
25     * [some thread ref] = running,
26     * DONE = completed normally,
27     * CANCELLED = cancelled (may or may not have ever run).
28     * Transitions use atomic updates.
29     */
30     private volatile Object runner;
31    
32 dl 1.5 /**
33 dl 1.1 * Special value for "runner" indicating task is completed
34     */
35     private static final Object DONE = new Object();
36    
37 dl 1.5 /**
38 dl 1.1 * Special value for "runner" indicating task is cancelled
39     */
40     private static final Object CANCELLED = new Object();
41    
42     private static AtomicReferenceFieldUpdater<CancellableTask, Object>
43 dl 1.9 runnerUpdater =
44     AtomicReferenceFieldUpdater.newUpdater
45     (CancellableTask.class, Object.class, "runner");
46 dl 1.1
47     /**
48     * The runnable underlying this task
49     */
50     private volatile Runnable runnable;
51    
52     /**
53 brian 1.4 * Creates a new CancellableTask which invokes the given
54     * <tt>Runnable</tt> when executed.
55 dl 1.5 * @param r the runnable action
56 dl 1.16 * @throws NullPointerException if runnable is null
57 dl 1.1 */
58     public CancellableTask(Runnable r) {
59 dl 1.16 if (r == null)
60     throw new NullPointerException();
61 dl 1.1 this.runnable = r;
62     }
63    
64     /**
65     * Creates a new CancellableTask without a runnable action, which
66     * must be set using <tt>setRunnable</tt> before use. This is
67     * intended for use in subclasses that must complete superclass
68 dl 1.14 * construction before establishing the runnable action.
69 dl 1.1 */
70     protected CancellableTask() {
71     }
72    
73    
74     public boolean cancel(boolean mayInterruptIfRunning) {
75     Object r = runner;
76     if (r == DONE || r == CANCELLED)
77     return false;
78    
79     if (mayInterruptIfRunning &&
80     r != null &&
81     r instanceof Thread &&
82 dl 1.3 runnerUpdater.compareAndSet(this, r, CANCELLED))
83 dl 1.1
84     ((Thread)r).interrupt();
85 dl 1.3 else
86 dl 1.1 runnerUpdater.set(this, CANCELLED);
87     return true;
88     }
89    
90     public boolean isCancelled() {
91     return runner == CANCELLED;
92     }
93    
94     public boolean isDone() {
95     Object r = runner;
96     return r == DONE || r == CANCELLED;
97     }
98    
99     /**
100     * Return the Runnable forming the basis of this task.
101 dl 1.5 * @return the runnable action
102 tim 1.10 * @see #setRunnable
103 dl 1.1 */
104     protected Runnable getRunnable() {
105     return runnable;
106     }
107    
108     /**
109     * Set the Runnable forming the basis of this task.
110 dl 1.5 * @param r the runnable action
111 tim 1.10 * @see #getRunnable
112 dl 1.1 */
113     protected void setRunnable(Runnable r) {
114     runnable = r;
115     }
116    
117     /**
118 tim 1.10 * Set the state of this task to Cancelled.
119 dl 1.1 */
120     protected void setCancelled() {
121     runnerUpdater.set(this, CANCELLED);
122     }
123    
124     /**
125     * Set the state of this task to Done, unless already
126     * in a Cancelled state, in which Cancelled status is preserved.
127     *
128     */
129     protected void setDone() {
130     for (;;) {
131     Object r = runner;
132     if (r == DONE || r == CANCELLED)
133     return;
134     if (runnerUpdater.compareAndSet(this, r, DONE))
135     return;
136     }
137     }
138    
139     /**
140     * Attempt to set the state of this task to Running, succeeding
141     * only if the state is currently NOT Done, Running, or Cancelled.
142 dl 1.2 * @return true if successful
143 dl 1.1 */
144     protected boolean setRunning() {
145     return runnerUpdater.compareAndSet(this, null, Thread.currentThread());
146     }
147    
148 dl 1.17 /**
149     * Runs the runnable if not cancelled, maintaining run status.
150     */
151 dl 1.1 public void run() {
152     if (setRunning()) {
153     try {
154     runnable.run();
155 tim 1.11 } finally {
156 dl 1.1 setDone();
157     }
158     }
159     }
160    
161     /**
162 dl 1.16 * Reset the run state of this task to its initial state unless
163     * it has been cancelled. (Note that a cancelled task cannot be
164     * reset.)
165     * @return true if successful
166 dl 1.15 */
167 dl 1.16 protected boolean reset() {
168     for (;;) {
169     Object r = runner;
170     if (r == CANCELLED)
171     return false;
172     if (runnerUpdater.compareAndSet(this, r, null))
173     return true;
174     }
175 dl 1.15 }
176    
177     /**
178 dl 1.1 * Implementation of Future methods under the control of a current
179 dl 1.13 * <tt>CancellableTask</tt>, which it relies on for methods
180     * <tt>isDone</tt>, <tt>isCancelled</tt> and <tt>cancel</tt>. This
181     * class is split into an inner class to permit Future support to
182     * be mixed-in with other flavors of tasks. Normally, such a
183     * class will delegate <tt>Future</tt> <tt>get</tt> methods to the
184     * <tt>InnerCancellableFuture</tt>, and internally arrange that
185     * <tt>set</tt> methods be invoked when computations are ready.
186     *
187     * <p><b>Sample Usage</b>. Here are fragments of an example subclass.
188     * <pre>
189 dl 1.19 * class MyFutureTask&lt;V&gt; extends CancellableTask implements Future&lt;V&gt; {
190 dl 1.13 *
191     * MyFutureTask(Callable&lt;V&gt; callable) {
192     * setRunnable(new InnerCancellableFuture&lt;V&gt;(callable));
193     * }
194     *
195     * public V get() throws InterruptedException, ExecutionException {
196     * return ((InnerCancellableFuture&lt;V&gt;)getRunnable()).get();
197     * }
198     * // (And similarly for timeout version.)
199     *
200     * void action() { // whatever action causes execution
201     * try {
202     * ((InnerCancellableFuture&lt;V&gt;)getRunnable()).set(compute());
203     * } catch (Exception ex) {
204     * ((InnerCancellableFuture&lt;V&gt;)getRunnable()).setException(ex);
205     * }
206     * }
207     * }
208     *</pre>
209 dl 1.1 */
210     protected class InnerCancellableFuture<V> implements Future<V>, Runnable {
211     private final Callable<V> callable;
212     private final ReentrantLock lock = new ReentrantLock();
213 dl 1.20 private final ReentrantLock.ConditionObject accessible = lock.newCondition();
214 dl 1.1 private V result;
215     private Throwable exception;
216 dl 1.5
217     /**
218     * Create an InnerCancellableFuture that will execute the
219     * given callable.
220     * @param callable the function to execute
221     */
222 dl 1.1 protected InnerCancellableFuture(Callable<V> callable) {
223     this.callable = callable;
224     }
225 tim 1.12
226     public boolean cancel(boolean mayInterruptIfRunning) {
227     return CancellableTask.this.cancel(mayInterruptIfRunning);
228     }
229    
230     public boolean isCancelled() {
231     return CancellableTask.this.isCancelled();
232     }
233    
234 dl 1.1
235     public boolean isDone() {
236     return CancellableTask.this.isDone();
237     }
238    
239 dl 1.13
240     /**
241     * Sets this Future to the results of <tt>callable.call</tt>
242     */
243 dl 1.1 public void run() {
244     try {
245     set(callable.call());
246 tim 1.11 } catch(Throwable ex) {
247 dl 1.1 setException(ex);
248     }
249     }
250    
251 dl 1.13 /**
252     * Waits if necessary for the call to <tt>callable.call</tt> to
253     * complete, and then retrieves its result.
254     *
255     * @return computed result
256     * @throws CancellationException here???
257     * @throws ExecutionException if underlying computation threw an
258     * exception
259     * @throws InterruptedException if current thread was interrupted
260     * while waiting
261     */
262 dl 1.1 public V get() throws InterruptedException, ExecutionException {
263     lock.lock();
264     try {
265     while (!isDone())
266     accessible.await();
267     if (isCancelled())
268     throw new CancellationException();
269     else if (exception != null)
270     throw new ExecutionException(exception);
271     else
272     return result;
273 tim 1.11 } finally {
274 dl 1.1 lock.unlock();
275     }
276     }
277    
278 dl 1.13 /**
279     * Waits if necessary for at most the given time for the call to
280     * <tt>callable.call</tt> to complete, and then retrieves its
281     * result.
282     *
283     * @param timeout the maximum time to wait
284 dl 1.14 * @param unit the time unit of the timeout argument
285 dl 1.13 * @return computed result
286     * @throws ExecutionException if underlying computation threw an
287     * exception
288     * @throws InterruptedException if current thread was interrupted
289     * while waiting
290     * @throws TimeoutException if the wait timed out
291     */
292 dl 1.1 public V get(long timeout, TimeUnit unit)
293     throws InterruptedException, ExecutionException, TimeoutException {
294     lock.lock();
295     try {
296     if (!isDone()) {
297     long nanos = unit.toNanos(timeout);
298     do {
299     if (nanos <= 0)
300     throw new TimeoutException();
301     nanos = accessible.awaitNanos(nanos);
302     } while (!isDone());
303     }
304     if (isCancelled())
305     throw new CancellationException();
306     else if (exception != null)
307     throw new ExecutionException(exception);
308     else
309     return result;
310 tim 1.11 } finally {
311 dl 1.1 lock.unlock();
312     }
313     }
314    
315 dl 1.13 /**
316     * Sets the result of this Future to the given value.
317     * @param v the value
318     */
319 dl 1.1 protected void set(V v) {
320     lock.lock();
321     try {
322     result = v;
323     setDone();
324     accessible.signalAll();
325 tim 1.11 } finally {
326 dl 1.1 lock.unlock();
327     }
328     }
329    
330 dl 1.13 /**
331 dl 1.18 * Causes this future to report an <tt>ExecutionException</tt>
332 dl 1.13 * with the given throwable as its cause.
333     * @param t the cause of failure.
334     */
335 dl 1.1 protected void setException(Throwable t) {
336     lock.lock();
337     try {
338     exception = t;
339     setDone();
340     accessible.signalAll();
341 tim 1.11 } finally {
342 dl 1.1 lock.unlock();
343     }
344     }
345     }
346    
347     }