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?
Looking at the source, The
Timer
class schedules tasks usingSystem.currentTimeMillis()
. TheScheduledThreadPoolExecutor
usesSystem.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 whilenanoTime()
should not.Timer
usesSystem.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.Timer
usesSystem.currentTimeMillis()
to determine the next execution of a task.However
ScheduledThreadPoolExecutor
usesSystem.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 clockSystem.nanoTime()
is not sensitive to system clock as it measures the time elapsed.Java Documentation:
System.nanoTime()