ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CancellableTask.java
Revision: 1.7
Committed: Sun Jul 13 22:51:51 2003 UTC (20 years, 11 months ago) by dl
Branch: MAIN
CVS Tags: JSR166_PRELIMINARY_TEST_RELEASE_2
Changes since 1.6: +0 -1 lines
Log Message:
Improve cancellation support; PBQs now use fair locks

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