Timer Does Not Run When Changing Computer Date

3

I have this simple timer that works normal. But when I change the date of the Retroactive computer the timer stops running. Can anyone explain me why ??

I need to know if the user has changed the computer date to block retroactive postings to the system.

Timer timer = new Timer();
timer.schedule(
        new TimerTask() {
            @Override
            public void run() {
                System.out.println(Funcao.dataAtual("dd/MM/yyyy"));
            }
        }, 0, 1000);
    
asked by anonymous 10.08.2016 / 14:02

3 answers

2

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).

    
10.08.2016 / 15:20
1

% w / w is dependent on the system date and time . If you happen to be back on time, I believe that according to this bug , it goes simply stop working. A viable option is to use something like java.util.Timer of scheduleAtFixedRate , which, being based on java.util.concurrent.ScheduledThreadPoolExecturor , is not based on the date and time of the OS:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Q146466 {
    public static void main(String[] args) {
        ScheduledThreadPoolExecutor sch = (ScheduledThreadPoolExecutor) 
                Executors.newScheduledThreadPool(5); // Pool de agendamento com 5 threads

        Runnable periodicTask = new Runnable(){
            @Override
            public void run() {
                // ...
            }
        };

        // Cria agendamento de tarefa para um intervalo de 5 segundos
        ScheduledFuture<?> periodicFuture = sch.scheduleAtFixedRate(periodicTask, 5, 5, TimeUnit.SECONDS);
    }
}

More details here and here .

    
10.08.2016 / 15:23
0

Thanks for the clarification Victor T.: D

I was able to resolve with Thread.

The operation stays the same as the timer and even better because it does not interfere with the current process. Here is an example

Thread thread = new Thread(() -> {
            while (true) {                
                try {
                    Thread.sleep(1000);
                    System.out.println("DataAtual: " + Funcao.dataAtual("dd/MM/yyyy"));
                } catch (InterruptedException ex) {
                    Logger.getLogger(MenuController.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        thread.start();
    
10.08.2016 / 16:54