ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CancellableTask.java
Revision: 1.9
Committed: Tue Aug 5 00:37:41 2003 UTC (20 years, 10 months ago) by dl
Branch: MAIN
Changes since 1.8: +3 -1 lines
Log Message:
Kill old JSR166Support

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