Timer does not run when changing computer date

Asked

Viewed 88 times

3

I have this simple timer that works normal. But when I change the computer date Retroactive the timer stops running. Someone can explain to me why??

I need to know if the user has changed the date of the computer to block retroactive releases on the system.

Timer timer = new Timer();
timer.schedule(
        new TimerTask() {
            @Override
            public void run() {
                System.out.println(Funcao.dataAtual("dd/MM/yyyy"));
            }
        }, 0, 1000);
  • What is the package of this class Timer? I ask this because I’ve seen more than one class with that name.

  • You are using java.util.Timer, correct? Doesn’t seem to be the javax.swing.Timer.

  • Hi, thank you for answering. I am using the import java.util.Timer; import java.util.Timertask packages;

  • Remember that changing the date and time should be administrative tasks. If it’s a matter of avoiding fraud, there’s nothing that a dedicated user with administrator powers won’t be able to circumvent.

3 answers

2

Looking in class source code java.util.Timer, these code snippets can be located:

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 (accompanying the class Timer, but it is not a public class), it is possible to locate the following within the method mainLoop():

                    currentTime = System.currentTimeMillis();
                    executionTime = task.nextExecutionTime;
                    if (taskFired = (executionTime<=currentTime)) {

That is, the method schedule look at the clock (using the method System.currentTimeMillis()), calculates a time in the future and calls the method sched, which uses the calculated time to define when the task shall be implemented. In the mainLoop() it picks up the time of the clock again (by means of the same method) and checks whether it has passed the time set to run the task.

This means that changing the date of the clock interferes with the class java.util.Timer. Changing the date back will postpone the execution of class tasks Timer. Changing the date forward will cause them to run before the time or even immediately.

The ideal would be to devise a solution based on the method System.nanoTime(), which means leaving the class java.util.Timer. The method nanoTime() does not suffer from this problem as it tells how much time has passed since some arbitrary point of time defined when the JVM is started (at least that’s what the documentation says, but I wouldn’t trust it before testing).

1

The java.util.Timer is dependent on the date and time of the system operational. If you happen to return the time, I believe that according to this bug, It’ll just stop working. A viable option is to use something like scheduleAtFixedRate of java.util.concurrent.ScheduledThreadPoolExecturor, which, being based on System.nanoTime, 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.

0

Thank you for the clarification Victor T. :D

I managed to solve with Thread.

The operation is the same as the timer and even better because it does not interfere with the current process.. Following 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();

Browser other questions tagged

You are not signed in. Login or sign up in order to post.