The Timer
(java.util.Timer
) doc describes the cancel
method as one that affects the Timer and it states that the timer cannot be used after cancellation. So I instantiate a new Timer
. Why will it not let me re-use the argument task0
in this example? I'm not even invoking purge
which is described as making tasks GC-eligible. Until it might be explained to be otherwise, I claim Timer
class should not affect a TimerTask
object that is merely an argument to it.
import java.util.Timer;
import java.util.TimerTask;
public class Tester {
public static void main(String[] args) throws InterruptedException {
long delay = 3000L;
Timer timer0 = new Timer();
Task task0 = new Task();
timer0.schedule(task0, delay);
timer0.cancel();
Timer timer1 = new Timer();
timer1.schedule(task0, delay); // throws an exception if we use task0
Thread.sleep(5000);
timer1.cancel();
}
}
class Task extends TimerTask {
Task() {
}
@Override
public void run() {
System.out.println("task was invoked");
}
}
Allowing this would be error prone, since task0
could still be running when scheduled again by another timer. (Note that cancel()
does not terminate the task.)
Note that if task0
is managed by a single Timer
, the same task will never be executed concurrently with itself (regardless if it is executed with fixed-delay or with fixed-rate).
If you really want such behavior, the work around would be to let task0
and a task1
wrap a common object:
class Task extends TimerTask {
Runnable runnable;
Task(Runnable runnable) {
this.runnable = runnable;
}
@Override
public void run() {
runnable.run();
}
}
And then execute it like this:
// "Wrapped" (and thus shared) by task0 and task1 below.
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("task was invoked");
}
}
Timer timer0 = new Timer();
Task task0 = new Task(runnable);
timer0.schedule(task0, delay);
timer0.cancel();
Task task1 = new Task(runnable);
Timer timer1 = new Timer();
timer1.schedule(task1, delay); // throws an exception if we use task0
Thread.sleep(5000);
timer1.cancel();
Take a look:
http://www.docjar.com/html/api/java/util/TimerTask.java.html
http://www.docjar.com/html/api/java/util/Timer.java.html
The TimerTask class is just a thin extension of Runnable which tracks a bit of metadata about scheduling (namely: next execution time). But, if you schedule it on two timers, there's still only one next execution field, so one timer would overwrite the next execution time of the other, which is almost certainly not what you want, so it tracks that it's been scheduled before, and throws an exception in Timer, instead.
If it allowed this, you'd get rather unexpected behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With