ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CancellableTask.java
Revision: 1.10
Committed: Wed Aug 6 18:22:09 2003 UTC (20 years, 10 months ago) by tim
Branch: MAIN
CVS Tags: JSR166_CR1
Changes since 1.9: +3 -1 lines
Log Message:
Fixes to minor errors found by DocCheck

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 * @see #setRunnable
99 */
100 protected Runnable getRunnable() {
101 return runnable;
102 }
103
104 /**
105 * Set the Runnable forming the basis of this task.
106 * @param r the runnable action
107 * @see #getRunnable
108 */
109 protected void setRunnable(Runnable r) {
110 runnable = r;
111 }
112
113 /**
114 * Set the state of this task to Cancelled.
115 */
116 protected void setCancelled() {
117 runnerUpdater.set(this, CANCELLED);
118 }
119
120 /**
121 * Set the state of this task to Done, unless already
122 * in a Cancelled state, in which Cancelled status is preserved.
123 *
124 */
125 protected void setDone() {
126 for (;;) {
127 Object r = runner;
128 if (r == DONE || r == CANCELLED)
129 return;
130 if (runnerUpdater.compareAndSet(this, r, DONE))
131 return;
132 }
133 }
134
135 /**
136 * Attempt to set the state of this task to Running, succeeding
137 * only if the state is currently NOT Done, Running, or Cancelled.
138 * @return true if successful
139 */
140 protected boolean setRunning() {
141 return runnerUpdater.compareAndSet(this, null, Thread.currentThread());
142 }
143
144 public void run() {
145 if (setRunning()) {
146 try {
147 runnable.run();
148 }
149 finally {
150 setDone();
151 }
152 }
153 }
154
155 /**
156 * Implementation of Future methods under the control of a current
157 * CancellableTask. This is split into an inner class to permit
158 * Future support to be mixed-in with other flavors of tasks.
159 */
160 protected class InnerCancellableFuture<V> implements Future<V>, Runnable {
161 private final Callable<V> callable;
162 private final ReentrantLock lock = new ReentrantLock();
163 private final Condition accessible = lock.newCondition();
164 private V result;
165 private Throwable exception;
166
167 /**
168 * Create an InnerCancellableFuture that will execute the
169 * given callable.
170 * @param callable the function to execute
171 */
172 protected InnerCancellableFuture(Callable<V> callable) {
173 this.callable = callable;
174 }
175
176 public boolean isDone() {
177 return CancellableTask.this.isDone();
178 }
179
180 public void run() {
181 try {
182 set(callable.call());
183 }
184 catch(Throwable ex) {
185 setException(ex);
186 }
187 }
188
189 public V get() throws InterruptedException, ExecutionException {
190 lock.lock();
191 try {
192 while (!isDone())
193 accessible.await();
194 if (isCancelled())
195 throw new CancellationException();
196 else if (exception != null)
197 throw new ExecutionException(exception);
198 else
199 return result;
200 }
201 finally {
202 lock.unlock();
203 }
204 }
205
206 public V get(long timeout, TimeUnit unit)
207 throws InterruptedException, ExecutionException, TimeoutException {
208 lock.lock();
209 try {
210 if (!isDone()) {
211 long nanos = unit.toNanos(timeout);
212 do {
213 if (nanos <= 0)
214 throw new TimeoutException();
215 nanos = accessible.awaitNanos(nanos);
216 } while (!isDone());
217 }
218 if (isCancelled())
219 throw new CancellationException();
220 else if (exception != null)
221 throw new ExecutionException(exception);
222 else
223 return result;
224 }
225 finally {
226 lock.unlock();
227 }
228 }
229
230 protected void set(V v) {
231 lock.lock();
232 try {
233 result = v;
234 setDone();
235 accessible.signalAll();
236 }
237 finally {
238 lock.unlock();
239 }
240 }
241
242 protected void setException(Throwable t) {
243 lock.lock();
244 try {
245 exception = t;
246 setDone();
247 accessible.signalAll();
248 }
249 finally {
250 lock.unlock();
251 }
252 }
253 }
254
255 }