A timer task is a background thread that is scheduled to run at a specific time by a timer object. Here's a possible implementation:
abstract class TimerTask implements Runnable, Comparable {
long period; // restart every period
msecs
long set; // next scheduled execution
time
public long scheduledExecutionTime() {
return set; }
public void cancel() { period = 0; }
public int compareTo(Object other) {
return
(int)(set - ((TimerTask)other).set);
}
}
Note that TimerTask is abstract because it doesn't implement run.
A timer is a thread that maintains a priority queue (implemented as a binary heap) of timer tasks prioritized by their scheduled execution times:
public class Timer extends Thread {
private PriorityQueue queue = new
BinaryHeap();
public Timer() { start(); } // create
then start
The run method perpetually:
1. deletes the next task
2. waits for its scheduled execution time
3. runs it
4. reschedules it if period > 0
Here's a possible implementation:
public void run() {
TimerTask
next;
while(true)
{
try
{
synchronized(queue)
{
next = (TimerTask)queue.deleteMin();
}
long
now = System.currentTimeMillis();
long
set = next.scheduledExecutionTime();
long
delay = set - now;
delay
= (0<delay)?delay:0;
synchronized(next)
{
next.wait((int)delay);
Thread thread = new Thread(next);
thread.start();
if
(0 < next.period) schedule(next, 0, next.period);
}
}
catch(Exception e) { /* try again */ }
}
}
Scheduling a task means computing its next execution time and inserting it back into the queue:
public void
schedule(TimerTask task, long delay) {
try {
synchronized(queue)
{
task.set
= System.currentTimeMillis() + delay;
queue.insert(task);
}
} catch(Exception e) { }
}
Scheduling a repeating task means specifying a period:
public void schedule(
TimerTask
task, long delay, long period) {
try {
task.period
= period;
task.set
= System.currentTimeMillis() + delay + period;
queue.insert(task);
} catch(Exception e) { }
}
// etc.
} // Timer
Running a test task prints its scheduled execution time (SET). After five runs it cancels itself:
class TestTask extends TimerTask {
private int id;
private int count = 0;
public String toString() { return
"task[" + id + "]"; }
public TestTask(int i) { id = i; }
public void run() {
long
time = scheduledExecutionTime();
System.out.println(toString()
+ " SET = " + time % 100000);
if (5 <= ++count) {
System.out.println(toString()
+ " cancelling itself");
cancel();
}
}
}
Our main method creates a timer and an array of test tasks:
public static void main(String[] args) {
Timer timer = new Timer(); // create a
new timer
// create a bunch ot test tasks:
TimerTask[] task = new TimerTask[10];
for(int i = 0; i < 10; i++) task[i]
= new TestTask(i);
// etc.
}
// after 1000, do task[0]
once
timer.schedule(task[0], 1000);
// after 1000, repeat task[1] every 500
timer.schedule(task[1], 1000, 500);
Date then = new Date(System.currentTimeMillis()
+ 2000);
// after 5000, do task[0] once
timer.schedule(task[2], then);
timer.scheduleAtFixedRate(task[3], 0,
100);
task[3] SET = 12583
task[3] SET = 12683
task[3] SET = 12783
task[3] SET = 12883
task[3] SET = 12983
task[3] cancelling itself
task[1] SET = 13585
task[0] SET = 13583
task[1] SET = 14086
task[2] SET = 14583
task[1] SET = 14586
task[1] SET = 15087
task[1] SET = 15588
task[1] cancelling itself
timer.scheduleAtFixedRate(task[3], 0, 100);
try {
System.out.println("timer sleeping
for 5000");
Thread.sleep(5000);
System.out.println("timer waking
up");
} catch(InterruptedException ie) {
System.err.println(ie.getMessage());
System.exit(1);
}
// after 500, do task[4] once
timer.schedule(task[4], 500);
try {
System.out.println("timer sleeping
for 5000");
Thread.sleep(5000);
System.out.println("timer waking
up and cancelling itself");
timer.cancel();
} catch(InterruptedException ie) {
System.err.println(ie.getMessage());
System.exit(1);
}
timer sleeping for 5000
task[3] SET = 64826
task[3] SET = 64926
task[3] SET = 65026
task[3] SET = 65126
task[3] SET = 65226
task[3] cancelling itself
timer waking up
timer sleeping for 5000
task[4] SET = 70323
timer waking up and cancelling itself