ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ScheduledExecutor.java
Revision: 1.6
Committed: Sat Jun 7 18:53:00 2003 UTC (21 years ago) by dl
Branch: MAIN
CVS Tags: JSR166_PRELIMINARY_TEST_RELEASE_1
Changes since 1.5: +54 -10 lines
Log Message:
Javadoc additions

File Contents

# User Rev Content
1 tim 1.1 /*
2 dl 1.4 * 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 tim 1.1 */
6    
7     package java.util.concurrent;
8 dl 1.4 import java.util.concurrent.atomic.*;
9 dl 1.2 import java.util.*;
10 tim 1.1
11     /**
12     * An <tt>Executor</tt> that can schedule tasks to run after a given delay,
13     * or to execute periodically. This class is preferable to
14     * <tt>java.util.Timer</tt> when multiple worker threads are needed,
15     * or when the additional flexibility or capabilities of
16     * <tt>ThreadExecutor</tt> are required. Tasks submitted using the
17     * <tt>execute</tt> method are scheduled as if they had a requested
18     * delay of zero.
19     *
20     * @since 1.5
21     * @see Executors
22     *
23     * @spec JSR-166
24     */
25     public class ScheduledExecutor extends ThreadPoolExecutor {
26    
27 dl 1.4 /**
28 dl 1.5 * Sequence number to break scheduling ties, and in turn to
29     * guarantee FIFO order among tied entries.
30     */
31     private static final AtomicLong sequencer = new AtomicLong(0);
32    
33     /**
34 dl 1.4 * A delayed or periodic action.
35     */
36 dl 1.5 public class DelayedTask extends CancellableTask implements Delayed {
37 dl 1.4 private final long sequenceNumber;
38     private final long time;
39     private final long period;
40    
41     /**
42 dl 1.5 * Creates a one-shot action with given nanoTime-based trigger time
43 dl 1.4 */
44     DelayedTask(Runnable r, long ns) {
45     super(r);
46     this.time = ns;
47     this.period = 0;
48     this.sequenceNumber = sequencer.getAndIncrement();
49     }
50    
51     /**
52 dl 1.5 * Creates a periodic action with given nano time and period
53 dl 1.4 */
54     DelayedTask(Runnable r, long ns, long period) {
55     super(r);
56     if (period <= 0)
57     throw new IllegalArgumentException();
58     this.time = ns;
59     this.period = period;
60     this.sequenceNumber = sequencer.getAndIncrement();
61     }
62    
63    
64     public long getDelay(TimeUnit unit) {
65     return unit.convert(time - TimeUnit.nanoTime(), TimeUnit.NANOSECONDS);
66     }
67    
68     public int compareTo(Object other) {
69     DelayedTask x = (DelayedTask)other;
70     long diff = time - x.time;
71     if (diff < 0)
72     return -1;
73     else if (diff > 0)
74     return 1;
75     else if (sequenceNumber < x.sequenceNumber)
76     return -1;
77     else
78     return 1;
79     }
80    
81 dl 1.5 public boolean cancel(boolean mayInterruptIfRunning) {
82     if (!isDone())
83     ScheduledExecutor.this.remove(this);
84     return super.cancel(mayInterruptIfRunning);
85     }
86    
87 dl 1.4 /**
88     * Return true if this is a periodic (not a one-shot) action.
89     */
90     public boolean isPeriodic() {
91     return period > 0;
92     }
93    
94     /**
95     * Returns the period, or zero if non-periodic
96     */
97     public long getPeriod(TimeUnit unit) {
98     return unit.convert(period, TimeUnit.NANOSECONDS);
99     }
100    
101     /**
102     * Return a new DelayedTask that will trigger in the period
103     * subsequent to current task, or null if non-periodic
104     * or canceled.
105     */
106 dl 1.5 DelayedTask nextTask() {
107 dl 1.4 if (period <= 0 || isCancelled())
108     return null;
109     return new DelayedTask(getRunnable(), time+period, period);
110     }
111 dl 1.2
112 dl 1.4 }
113 dl 1.2
114 dl 1.4 /**
115     * A delayed result-bearing action.
116     */
117 dl 1.5 public class DelayedFutureTask<V> extends DelayedTask implements Future<V> {
118 dl 1.4 /**
119     * Creates a Future that may trigger after the given delay.
120     */
121     DelayedFutureTask(Callable<V> callable, long delay, TimeUnit unit) {
122     // must set after super ctor call to use inner class
123     super(null, TimeUnit.nanoTime() + unit.toNanos(delay));
124     setRunnable(new InnerCancellableFuture<V>(callable));
125 dl 1.2 }
126    
127 dl 1.4 /**
128     * Creates a one-shot action that may trigger after the given date.
129     */
130     DelayedFutureTask(Callable<V> callable, Date date) {
131     super(null,
132     TimeUnit.MILLISECONDS.toNanos(date.getTime() -
133     System.currentTimeMillis()));
134     setRunnable(new InnerCancellableFuture<V>(callable));
135     }
136    
137     public V get() throws InterruptedException, ExecutionException {
138     return ((InnerCancellableFuture<V>)getRunnable()).get();
139 dl 1.2 }
140    
141 dl 1.4 public V get(long timeout, TimeUnit unit)
142     throws InterruptedException, ExecutionException, TimeoutException {
143     return ((InnerCancellableFuture<V>)getRunnable()).get(timeout, unit);
144 dl 1.2 }
145 tim 1.1
146 dl 1.4 protected void set(V v) {
147     ((InnerCancellableFuture<V>)getRunnable()).set(v);
148 dl 1.2 }
149 tim 1.1
150 dl 1.4 protected void setException(Throwable t) {
151     ((InnerCancellableFuture<V>)getRunnable()).setException(t);
152     }
153     }
154    
155    
156     /**
157     * An annoying wrapper class to convince generics compiler to
158     * use a DelayQueue<DelayedTask> as a BlockingQUeue<Runnable>
159     */
160     private static class DelayedWorkQueue extends AbstractQueue<Runnable> implements BlockingQueue<Runnable> {
161     private final DelayQueue<DelayedTask> dq = new DelayQueue<DelayedTask>();
162     public Runnable poll() { return dq.poll(); }
163     public Runnable peek() { return dq.peek(); }
164     public Runnable take() throws InterruptedException { return dq.take(); }
165     public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException {
166     return dq.poll(timeout, unit);
167 dl 1.2 }
168 dl 1.4 public boolean offer(Runnable x) { return dq.offer((DelayedTask)x); }
169     public void put(Runnable x) throws InterruptedException {
170     dq.put((DelayedTask)x);
171 dl 1.2 }
172 dl 1.4 public boolean offer(Runnable x, long timeout, TimeUnit unit) throws InterruptedException {
173     return dq.offer((DelayedTask)x, timeout, unit);
174 dl 1.2 }
175 dl 1.4 public int remainingCapacity() { return dq.remainingCapacity(); }
176     public boolean remove(Object x) { return dq.remove(x); }
177     public boolean contains(Object x) { return dq.contains(x); }
178     public int size() { return dq.size(); }
179     public boolean isEmpty() { return dq.isEmpty(); }
180     public Iterator<Runnable> iterator() {
181     return new Iterator<Runnable>() {
182     private Iterator<DelayedTask> it = dq.iterator();
183     public boolean hasNext() { return it.hasNext(); }
184     public Runnable next() { return it.next(); }
185     public void remove() { it.remove(); }
186     };
187 tim 1.1 }
188 dl 1.4 }
189 tim 1.1
190 dl 1.4 /**
191     * Creates a new ScheduledExecutor with the given initial parameters.
192     *
193     * @param corePoolSize the number of threads to keep in the pool,
194     * even if they are idle.
195     */
196     public ScheduledExecutor(int corePoolSize) {
197     super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
198     new DelayedWorkQueue());
199     }
200 tim 1.1
201 dl 1.4 /**
202     * Creates a new ScheduledExecutor with the given initial parameters.
203     *
204     * @param corePoolSize the number of threads to keep in the pool,
205     * even if they are idle.
206     * @param threadFactory the factory to use when the executor
207     * creates a new thread.
208     */
209     public ScheduledExecutor(int corePoolSize,
210     ThreadFactory threadFactory) {
211     super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
212     new DelayedWorkQueue(), threadFactory);
213 tim 1.1 }
214    
215 dl 1.4 /**
216     * Creates a new ScheduledExecutor with the given initial parameters.
217     *
218     * @param corePoolSize the number of threads to keep in the pool,
219     * even if they are idle.
220     * @param handler the handler to use when execution is blocked
221     * because the thread bounds and queue capacities are reached.
222     */
223     public ScheduledExecutor(int corePoolSize,
224     RejectedExecutionHandler handler) {
225     super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
226     new DelayedWorkQueue(), handler);
227     }
228 dl 1.2
229 tim 1.1 /**
230 dl 1.2 * Creates a new ScheduledExecutor with the given initial parameters.
231     *
232     * @param corePoolSize the number of threads to keep in the pool,
233     * even if they are idle.
234 dl 1.4 * @param threadFactory the factory to use when the executor
235     * creates a new thread.
236     * @param handler the handler to use when execution is blocked
237     * because the thread bounds and queue capacities are reached.
238 tim 1.1 */
239 dl 1.4 public ScheduledExecutor(int corePoolSize,
240     ThreadFactory threadFactory,
241     RejectedExecutionHandler handler) {
242 dl 1.2 super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
243 dl 1.4 new DelayedWorkQueue(), threadFactory, handler);
244     }
245    
246     /**
247     * Creates and executes a one-shot action that may trigger after
248     * the given delay.
249 dl 1.6 * @param command the task to execute.
250     * @param delay the time from now to delay execution.
251     * @param unit the time unit of the delay parameter.
252     * @return a handle that can be used to cancel the task.
253 dl 1.4 */
254    
255 dl 1.6 public DelayedTask schedule(Runnable command, long delay, TimeUnit unit) {
256     DelayedTask t = new DelayedTask(command, TimeUnit.nanoTime() + unit.toNanos(delay));
257 dl 1.4 super.execute(t);
258     return t;
259     }
260    
261     /**
262     * Creates and executes a one-shot action that may trigger after the given date.
263 dl 1.6 * @param command the task to execute.
264     * @param date the time to commence excution.
265     * @return a handle that can be used to cancel the task.
266     * @throws RejectedExecutionException if task cannot be scheduled
267     * for execution because the executor has been shut down.
268 dl 1.4 */
269 dl 1.6 public DelayedTask schedule(Runnable command, Date date) {
270 dl 1.4 DelayedTask t = new DelayedTask
271 dl 1.6 (command,
272 dl 1.4 TimeUnit.MILLISECONDS.toNanos(date.getTime() -
273     System.currentTimeMillis()));
274     super.execute(t);
275     return t;
276     }
277    
278     /**
279     * Creates and executes a periodic action that may trigger first
280     * after the given initial delay, and subsequently with the given
281     * period.
282 dl 1.6 * @param command the task to execute.
283     * @param initialDelay the time to delay first execution.
284     * @param period the period between successive executions.
285     * @param unit the time unit of the delay and period parameters
286     * @return a handle that can be used to cancel the task.
287     * @throws RejectedExecutionException if task cannot be scheduled
288     * for execution because the executor has been shut down.
289 dl 1.4 */
290 dl 1.6 public DelayedTask schedule (Runnable command, long initialDelay, long period, TimeUnit unit) {
291 dl 1.4 DelayedTask t = new DelayedTask
292 dl 1.6 (command, TimeUnit.nanoTime() + unit.toNanos(initialDelay),
293 dl 1.4 unit.toNanos(period));
294     super.execute(t);
295     return t;
296     }
297    
298     /**
299     * Creates a periodic action that may trigger first after the
300     * given date, and subsequently with the given period.
301 dl 1.6 * @param command the task to execute.
302     * @param initialDate the time to delay first execution.
303     * @param period the period between successive executions.
304     * @param unit the time unit of the period parameter.
305     * @return a handle that can be used to cancel the task.
306     * @throws RejectedExecutionException if task cannot be scheduled
307     * for execution because the executor has been shut down.
308 dl 1.4 */
309 dl 1.6 public DelayedTask schedule(Runnable command, Date initialDate, long period, TimeUnit unit) {
310 dl 1.4 DelayedTask t = new DelayedTask
311 dl 1.6 (command,
312     TimeUnit.MILLISECONDS.toNanos(initialDate.getTime() -
313 dl 1.4 System.currentTimeMillis()),
314     unit.toNanos(period));
315     super.execute(t);
316     return t;
317 tim 1.1 }
318    
319    
320 dl 1.4 /**
321     * Creates and executes a Future that may trigger after the given delay.
322 dl 1.6 * @param callable the function to execute.
323     * @param delay the time from now to delay execution.
324     * @param unit the time unit of the delay parameter.
325     * @return a Future that can be used to extract result or cancel.
326     * @throws RejectedExecutionException if task cannot be scheduled
327     * for execution because the executor has been shut down.
328 dl 1.4 */
329     public <V> DelayedFutureTask<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
330     DelayedFutureTask<V> t = new DelayedFutureTask<V>
331     (callable, delay, unit);
332     super.execute(t);
333     return t;
334     }
335    
336     /**
337     * Creates and executes a one-shot action that may trigger after
338     * the given date.
339 dl 1.6 * @param callable the function to execute.
340     * @param date the time to commence excution.
341     * @return a Future that can be used to extract result or cancel.
342     * @throws RejectedExecutionException if task cannot be scheduled
343     * for execution because the executor has been shut down.
344 dl 1.4 */
345     public <V> DelayedFutureTask<V> schedule(Callable<V> callable, Date date) {
346     DelayedFutureTask<V> t = new DelayedFutureTask<V>
347     (callable, date);
348     super.execute(t);
349     return t;
350 tim 1.1 }
351    
352 dl 1.4 /**
353     * Execute command with zero required delay
354 dl 1.6 * @param command the task to execute
355     * @throws RejectedExecutionException at discretion of
356     * <tt>RejectedExecutionHandler</tt>, if task cannot be accepted
357     * for execution because the executor has been shut down.
358 dl 1.4 */
359     public void execute(Runnable command) {
360     schedule(command, 0, TimeUnit.NANOSECONDS);
361 tim 1.1 }
362    
363 dl 1.4 /**
364     * If executed task was periodic, cause the task for the next
365     * period to execute.
366     */
367     protected void afterExecute(Runnable r, Throwable t) {
368     if (isShutdown())
369     return;
370     super.afterExecute(r, t);
371     DelayedTask d = (DelayedTask)r;
372     DelayedTask next = d.nextTask();
373 dl 1.6 if (next == null)
374     return;
375     try {
376 dl 1.4 super.execute(next);
377 dl 1.6 }
378     catch(RejectedExecutionException ex) {
379     // lost race to detect shutdown; ignore
380     }
381 dl 1.4 }
382 tim 1.1 }
383 dl 1.4
384