0

I'm having a few issues with scheduling a task to run in my code every minute.

I have tried many ways to do this such as:

Timer timer = new Timer();

timer.schedule( new TimerTask() {
    public void run() {
       printTime();
    }
 }, 0, 60*1000);

And also:

ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
Runnable task = () -> {
    printTime();
};
executor.scheduleWithFixedDelay(task, 0, 1, TimeUnit.MINUTES);

These both print out erratic times not even close to the times I have provided:

2019-12-03T12:48:23.300
2019-12-03T12:48:24.700
2019-12-03T12:48:41.895
2019-12-03T12:48:42.799
2019-12-03T12:48:47.189
2019-12-03T12:48:47.211
2019-12-03T12:48:47.278

These are the times I get, totally wrong and some are within seconds! Is there an accurate way for me to schedule a task to run every minute while my code preforms other tasks?

My plan was to calculate the times between when the task is fired but Timer and ScheduledExecutor seems to wait longer than the time provided also not only shorter. So this means it would also be off.

Stefza
  • 247
  • 3
  • 18

2 Answers2

2

I run below code and it is working as expected

public class Test {
    public static void main(String[] args)  {
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
        Runnable task = () -> printTime();
        executor.scheduleWithFixedDelay(task, 0, 1, TimeUnit.MINUTES);
    }

    private static void printTime() {
        System.out.println(new Date());
    }
}

Output is:

Tue Dec 03 16:06:31 EET 2019
Tue Dec 03 16:07:31 EET 2019
Tue Dec 03 16:08:31 EET 2019
Tue Dec 03 16:09:31 EET 2019

Probably, you are running multiple instance of TimerTask. You can extract your code to an utility class to ensure you have only one instance.

    public enum  PrintTimer {
        INSTANCE;

        private boolean running = false;

        private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

        public synchronized void start()  {
            if (!running) {
                running = true;
                Runnable task = () -> printTime();
                executor.scheduleWithFixedDelay(task, 0, 1, TimeUnit.MINUTES);
            }
        }

        private static void printTime() {
            System.out.println(LocalDateTime.now());
        }
    }

You can call it like:

PrintTimer.INSTANCE.start();
savas
  • 241
  • 2
  • 9
  • The print time method has only 1 line of code which uses System.out.println() to display the time. The timing is off somewhere or it is somehow being reset, I don't actually know. – Stefza Dec 03 '19 at 14:29
  • Could you share rest of the code and OS, JVM details? – savas Dec 03 '19 at 14:32
  • I'm using Windows 10 with Java Oracle Version 8. This happens on multiple machines including the server which is Debian. This is all Vaadin code which I feel might be the issue – Stefza Dec 03 '19 at 14:38
  • Maybe your are calling the code from more than one thread if you are running in multi-threaded environment. You can add logs to trace the issue if you don't have any log after scheduleWithFixedDelay method. – savas Dec 03 '19 at 14:43
  • Doesn't `Executors.newScheduledThreadPool(1)` assign it to 1 thread? – Stefza Dec 03 '19 at 14:46
  • Yes, but it is possible to call it from more then one thread. Then you will have multiple scheduled threads. – savas Dec 03 '19 at 14:48
  • How would I work around this then? I would only like 1 scheduled thread. – Stefza Dec 03 '19 at 15:09
  • You can make an utility class and ensure executor.scheduleWithFixedDelay is called only once. Also add synchronization to prevent race conditions. – savas Dec 03 '19 at 15:18
1

Both of them works

Runnable task = () -> System.out.println("Executor: " + LocalDateTime.now());
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

executor.scheduleWithFixedDelay(task, 0, 1, TimeUnit.MINUTES);

and

new Timer().schedule(new TimerTask() {
    public void run() {
        System.out.println("Timer: " + LocalDateTime.now());
    }
}, 0, 60*1000);

Output

Timer: 2019-12-03T15:29:25.931
Executor: 2019-12-03T15:29:25.931
Timer: 2019-12-03T15:30:25.904
Executor: 2019-12-03T15:30:25.934
Timer: 2019-12-03T15:31:25.904
Executor: 2019-12-03T15:31:25.935
Timer: 2019-12-03T15:32:25.905
Executor: 2019-12-03T15:32:25.937

If you can choose, better use ScheduledExecutorService (Java Timer vs ExecutorService)

Butiri Dan
  • 1,759
  • 5
  • 12
  • 18