ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CancellableTask.java
Revision: 1.4
Committed: Mon Jun 23 02:26:16 2003 UTC (20 years, 11 months ago) by brian
Branch: MAIN
Changes since 1.3: +2 -2 lines
Log Message:
Partial javadoc pass

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    
10     /**
11     * Base class for cancellable actions running in the Executor
12     * framework. In addition to serving as a standalone class, this
13     * provides <tt>protected</tt> functionality that may be useful when
14     * creating customized task classes.
15     */
16    
17     public class CancellableTask implements Cancellable, Runnable {
18     /**
19     * Holds the run-state, taking on values:
20     * null = not yet started,
21     * [some thread ref] = running,
22     * DONE = completed normally,
23     * CANCELLED = cancelled (may or may not have ever run).
24     * Transitions use atomic updates.
25     */
26     private volatile Object runner;
27    
28     /*
29     * Special value for "runner" indicating task is completed
30     */
31     private static final Object DONE = new Object();
32    
33     /*
34     * Special value for "runner" indicating task is cancelled
35     */
36     private static final Object CANCELLED = new Object();
37    
38     private static AtomicReferenceFieldUpdater<CancellableTask, Object>
39     runnerUpdater = new AtomicReferenceFieldUpdater<CancellableTask, Object>(new CancellableTask[0], new Object[0], "runner");
40    
41     /**
42     * The runnable underlying this task
43     */
44     private volatile Runnable runnable;
45    
46     /**
47 brian 1.4 * Creates a new CancellableTask which invokes the given
48     * <tt>Runnable</tt> when executed.
49 dl 1.1 */
50     public CancellableTask(Runnable r) {
51     this.runnable = r;
52     }
53    
54     /**
55     * Creates a new CancellableTask without a runnable action, which
56     * must be set using <tt>setRunnable</tt> before use. This is
57     * intended for use in subclasses that must complete superclass
58     * construction beofre establishing the runnable action.
59     */
60     protected CancellableTask() {
61     }
62    
63    
64     public boolean cancel(boolean mayInterruptIfRunning) {
65     Object r = runner;
66     if (r == DONE || r == CANCELLED)
67     return false;
68    
69     if (mayInterruptIfRunning &&
70     r != null &&
71     r instanceof Thread &&
72     r != Thread.currentThread() &&
73 dl 1.3 runnerUpdater.compareAndSet(this, r, CANCELLED))
74 dl 1.1
75     ((Thread)r).interrupt();
76 dl 1.3 else
77 dl 1.1 runnerUpdater.set(this, CANCELLED);
78     return true;
79     }
80    
81     public boolean isCancelled() {
82     return runner == CANCELLED;
83     }
84    
85     public boolean isDone() {
86     Object r = runner;
87     return r == DONE || r == CANCELLED;
88     }
89    
90     /**
91     * Return the Runnable forming the basis of this task.
92     */
93     protected Runnable getRunnable() {
94     return runnable;
95     }
96    
97     /**
98     * Set the Runnable forming the basis of this task.
99     */
100     protected void setRunnable(Runnable r) {
101     runnable = r;
102     }
103    
104     /**
105     * Set the state of this task to Cancelled
106     */
107     protected void setCancelled() {
108     runnerUpdater.set(this, CANCELLED);
109     }
110    
111     /**
112     * Set the state of this task to Done, unless already
113     * in a Cancelled state, in which Cancelled status is preserved.
114     *
115     */
116     protected void setDone() {
117     for (;;) {
118     Object r = runner;
119     if (r == DONE || r == CANCELLED)
120     return;
121     if (runnerUpdater.compareAndSet(this, r, DONE))
122     return;
123     }
124     }
125    
126     /**
127     * Attempt to set the state of this task to Running, succeeding
128     * only if the state is currently NOT Done, Running, or Cancelled.
129 dl 1.2 * @return true if successful
130 dl 1.1 */
131     protected boolean setRunning() {
132     return runnerUpdater.compareAndSet(this, null, Thread.currentThread());
133     }
134    
135     public void run() {
136     if (setRunning()) {
137     try {
138     runnable.run();
139     }
140     finally {
141     setDone();
142     }
143     }
144     }
145    
146     /**
147     * Implementation of Future methods under the control of a current
148     * CancellableTask. This is split into an inner class to permit
149     * Future support to be mixed-in with other flavors of tasks.
150     */
151     protected class InnerCancellableFuture<V> implements Future<V>, Runnable {
152     private final Callable<V> callable;
153     private final ReentrantLock lock = new ReentrantLock();
154     private final Condition accessible = lock.newCondition();
155     private V result;
156     private Throwable exception;
157     protected InnerCancellableFuture(Callable<V> callable) {
158     this.callable = callable;
159     }
160    
161     public boolean isDone() {
162     return CancellableTask.this.isDone();
163     }
164    
165     public void run() {
166     try {
167     set(callable.call());
168     }
169     catch(Throwable ex) {
170     setException(ex);
171     }
172     }
173    
174     public V get() throws InterruptedException, ExecutionException {
175     lock.lock();
176     try {
177     while (!isDone())
178     accessible.await();
179     if (isCancelled())
180     throw new CancellationException();
181     else if (exception != null)
182     throw new ExecutionException(exception);
183     else
184     return result;
185     }
186     finally {
187     lock.unlock();
188     }
189     }
190    
191     public V get(long timeout, TimeUnit unit)
192     throws InterruptedException, ExecutionException, TimeoutException {
193     lock.lock();
194     try {
195     if (!isDone()) {
196     long nanos = unit.toNanos(timeout);
197     do {
198     if (nanos <= 0)
199     throw new TimeoutException();
200     nanos = accessible.awaitNanos(nanos);
201     } while (!isDone());
202     }
203     if (isCancelled())
204     throw new CancellationException();
205     else if (exception != null)
206     throw new ExecutionException(exception);
207     else
208     return result;
209     }
210     finally {
211     lock.unlock();
212     }
213     }
214    
215     protected void set(V v) {
216     lock.lock();
217     try {
218     result = v;
219     setDone();
220     accessible.signalAll();
221     }
222     finally {
223     lock.unlock();
224     }
225     }
226    
227     protected void setException(Throwable t) {
228     lock.lock();
229     try {
230     exception = t;
231     setDone();
232     accessible.signalAll();
233     }
234     finally {
235     lock.unlock();
236     }
237     }
238     }
239    
240     }