9

This highly voted answer on SO regarding the differences between a Timer and a ScheduledThreadPoolExecutor mentions the following while enumerating the differences:

Timer can be sensitive to changes in the system clock, ScheduledThreadPoolExecutor isn't.

The above is mentioned verbatim inside the great book Java Concurrency in Practice.

I understand the points mentioned in that answer except the above mentioned one. What does it mean to say that Timers can be sensitive to system clock whereas ScheduledThreadPoolExecutors are not?

Community
  • 1
  • 1
Geek
  • 23,609
  • 39
  • 133
  • 212
  • Check this: http://stackoverflow.com/questions/17588167/what-should-timertask-scheduleatfixedrate-do-if-the-clock-changes – Juned Ahsan Sep 14 '13 at 16:19

3 Answers3

10

Timer uses System.currentTimeMillis(), which represents wall clock time and should never be used for checking relative times such as determining how long something took to run or, in this case, how long to delay before executing a task. System.currentTimeMillis() is affected by things like automatic adjustments to the system clock or even manually changing the system clock. As such, if you call it twice and check the difference between the times you get, you can even get a negative number.

System.nanoTime(), on the other hand, is specifically intended for measuring elapsed time and is what should be used for this sort of thing.

ColinD
  • 103,631
  • 27
  • 195
  • 199
  • What do you mean by automatic adjustment to the system clock? – Geek Sep 15 '13 at 12:29
  • 1
    @Geek: The system clock can get slightly off over time, requiring small adjustments to keep it correct (for example, if it's syncing with a central time server). I believe that there can also be adjustments for dealing with things like leap seconds. – ColinD Sep 15 '13 at 14:23
5

Timer uses System.currentTimeMillis() to determine the next execution of a task.

However ScheduledThreadPoolExecutor uses System.nanoTime().

Also nanoTime() method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time.

System.currentTimeMillis() is sensitive to system clock

System.nanoTime() is not sensitive to system clock as it measures the time elapsed.

Java Documentation: System.nanoTime()

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 time (perhaps in the future, so values may be negative).

Narendra Pathai
  • 38,384
  • 18
  • 73
  • 117
  • The docs also say the reference point doesn't change while the JVM is running, unless it runs more than approx 292 years, but the reference point is likely to be different between instances of the JVM both locally and remote. – nexus_2006 Sep 14 '13 at 16:43
  • 1
    @nexus_2006 What difference does that make to scheduling of tasks on local machine? – Narendra Pathai Sep 14 '13 at 16:45
  • I just thought it was interesting note, when you use the ThreadPoolExecutor class I suppose it doesn't make a difference. I'm not very familiar with that class, but it looks like you only can set a delay, not an exact clock time, but I could be wrong. When using the nanoTime() directly in your app, its not a time, just a marker. The docs say its not guaranteed to be any more accurate than currentTimeMillis(). Just thought the differences were interesting – nexus_2006 Sep 14 '13 at 20:34
1

Looking at the source, The Timer class schedules tasks using System.currentTimeMillis(). The ScheduledThreadPoolExecutor uses System.nanoTime().

currentTimeMillis() will tend to use the OS clock, the one that tracks the current date/time. nanoTime() will tend to use a higher resolution hardware clock.

If you move your OS clock back an hour, then currentTimeMillis() could should reflect that while nanoTime() should not.

Kemick
  • 91
  • 2