ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CancellableTask.java
Revision: 1.25
Committed: Thu Dec 4 20:54:28 2003 UTC (20 years, 5 months ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.24: +0 -0 lines
State: FILE REMOVED
Log Message:
Revised tests for revised Future classes

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