Looking at the source code of the java.util.Timer
class, these code snippets can be found:
public void schedule(TimerTask task, long delay, long period) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, System.currentTimeMillis()+delay, -period);
}
private void sched(TimerTask task, long time, long period) {
// [um monte de código] ...
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
// [mais um monte de código] ...
}
In class TimerThread
(which accompanies class Timer
, but is not a public class), you can find the following within method mainLoop()
:
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime<=currentTime)) {
That is, the schedule
method looks at the clock (using the System.currentTimeMillis()
"), calculates a time in the future, and calls the sched
method, which uses the calculated time to set when task
is executed. In the mainLoop()
method, it picks the clock time again (using the same method) and checks if it is past its scheduled time to run task
.
This means that changing the date of the clock interferes with the java.util.Timer
class. Changing the date backward will delay the execution of the tasks of class Timer
. Changing the date forward will make them run ahead of time or even immediately.
Ideally, you should design a solution based on the System.nanoTime()
, which means dropping the java.util.Timer
class. The nanoTime()
method does not suffer from this problem because it counts how much time has passed from some arbitrary point of time defined when the JVM is started (at least that's what the documentation says, but I would not trust it before testing).