ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CancellableTask.java
Revision: 1.3
Committed: Mon Jun 9 02:32:05 2003 UTC (21 years ago) by dl
Branch: MAIN
Changes since 1.2: +2 -4 lines
Log Message:
New ScheduledExecuor methods; minor javadoc cleanup

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
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 * Creates a new CancellableTask invoking the given
48 * runnable when executed.
49 */
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 runnerUpdater.compareAndSet(this, r, CANCELLED))
74
75 ((Thread)r).interrupt();
76 else
77 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 * @return true if successful
130 */
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 }