Why can't TimerTask be reused with a new Timer object?

The Timer document ( java.util.Timer ) describes the cancel method as the one that affects the timer, and it states that the timer cannot be used after cancellation. Therefore, I am creating a new Timer . Why won't this allow me to reuse the task0 argument in this example? I do not even call purge , which is described as performing tasks GC-right. Unless otherwise explained, I argue that the Timer class should not affect the TimerTask object, which is just an argument for 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"); } } 
+7
source share
3 answers

Resolving this will be error prone, as task0 can still work when resubmitted by another timer. (Note that cancel() does not complete the task.)

Note that if task0 controlled by a single Timer , the same task will never be executed simultaneously with itself (regardless of whether it runs with a fixed delay or a fixed speed).

If you really want this behavior, the job should be to let task0 and task1 wrap the shared object:

 class Task extends TimerTask { Runnable runnable; Task(Runnable runnable) { this.runnable = runnable; } @Override public void run() { runnable.run(); } } 

And then do 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(); 
+4
source

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 subtle Runnable extension that keeps track of a bit of planning metadata (namely: the next run time). But if you plan it for two timers, there is only one next execution field left, so one timer will overwrite the next execution time of the other, which is almost certainly not what you want, therefore it keeps track of what it was scheduled earlier and throws an exception instead in the timer.

If this is acceptable, you will get pretty unexpected behavior.

+1
source

This is also a problem if the timer task wants to redistribute itself in the same timer - possibly with a different delay this time. This would allow me, for example, to implement something like an exponential delay algorithm (repeat the task with exponentially increasing delays.

It seems that such a timer task with variable delays can be most likely implemented using ScheduledExecutorService, because this class does not create such restrictions.

0
source

All Articles