ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CancellableTask.java
Revision: 1.2
Committed: Fri Jun 6 16:53:04 2003 UTC (21 years ago) by dl
Branch: MAIN
CVS Tags: JSR166_PRELIMINARY_TEST_RELEASE_1
Changes since 1.1: +1 -1 lines
Log Message:
Minor doc updates; FairReentrantLock serialize now

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