6

We want to run a task every 1000 seconds (say).

So we have

timer.scheduleAtFixedRate(task, delay, interval);

Mostly, this works fine. However, this is an embedded system and the user can change the real time clock. If they set it to a time in the past after we set up the timer, it seems the timer doesn't execute until the original real-time date/time. So if they set it back 3 days, the timer doesn't execute for 3 days :(

Is this permissible behaviour, or a defect in the Java library? The Oracle javadocs don't seem to mention anything about the dependency or not on the underlying value of the system clock.

If it's permissible, how do we spot this clock change and reschedule our timers?

The Archetypal Paul
  • 39,479
  • 18
  • 96
  • 128
  • if you set the time forward 3 days it executes infinity (not quite but you know what i mean) times trying to catch up!! – pstanton Jan 08 '18 at 09:17

2 Answers2

17

Looking at the source of Timer for Java 1.7, it appears that is uses System.currentTimeMillis() to determine the next execution of a task.

However, looking at the source of ScheduledThreadPoolExecutor, it uses System.nanoTime().

Which means you won't see that behaviour if you use one in place of a Timer. To create one, use, for instance, Executors.newScheduledThreadPool().

Why you wouldn't see this behaviour is because of what the doc for System.nanoTime() says:

This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary origin time [emphasis mine].

As to whether this is a bug in Timer, maybe...

Note that unlike a ScheduledExecutorService, a Timer supports absolute time, and maybe this explains its use of System.currentTimeMillis(); also, Timer has been there since Java 1.3 while System.nanoTime() only appears in 1.5.

But a consequence of using System.currentTimeMillis() is that Timer is sensitive to the system date/time... And that is not documented in the javadoc.

fge
  • 110,072
  • 26
  • 223
  • 312
  • 3
    +1 Was looking at the source and got to the same conclusion. It should probably be documented a little better. – assylias Jul 11 '13 at 08:22
  • Looks just what I need, but is Java 1.5 or greater. We have to use 1.4 :( Backports (of JSR-166) exist but still rely on some kind of real time clock that isn't affected by changes to date/time settings. Still looking to see if such a thing exists in our environment... – The Archetypal Paul Jul 16 '13 at 10:46
  • Uh, sorry, I don't do 1.4 at all :( I know of a package named backport-util-concurrent, but indeed `System.nanoTime()` is another matter... If 1.4 I guess only native code can provide that. – fge Jul 16 '13 at 12:22
5

It is reported here http://bugs.sun.com/view_bug.do?bug_id=4290274

Similarly, when the system clock is set to a later time, the task may be run multiple times without any delay to "catch up" the missed executions. Exactly this happens when the computer is set to standby/hibernate and the application is resumed (this is how I found out).

This behavior can also be seen in a Java debugger by suspending the timer thread and resuming it.

Henno Vermeulen
  • 1,427
  • 2
  • 15
  • 25
  • 1
    " Similarly, when the system clock is set to a later time, the task may be run multiple times". This seems to depend. We have a IBM j9 system where this doesn't seem to happen, but instead it fires once, some time later not obviously connected with the repeat period, and subsequently repeats as expected. We've not characterised this fully yet though. We're looking at moving to ScheduledExecutorService – The Archetypal Paul Jul 31 '13 at 10:17
  • Ok that's interesting. We are using Oracle Java on Windows. – Henno Vermeulen Aug 01 '13 at 12:05