为什么 Java Scheduler 在 Windows 上表现出明显的时间漂移?
我有在Windows 7上运行的Java服务,该服务每天在上运行一次。我从来没有给过太多,因为它不是关键的,但最近查看了数字,发现该服务每天漂移大约15分钟,这听起来太多了。SingleThreadScheduledExecutor
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
long drift = (System.currentTimeMillis() - lastTimeStamp - seconds * 1000);
lastTimeStamp = System.currentTimeMillis();
}, 0, 10, TimeUnit.SECONDS);
这种方法每10秒漂移一致。如果我以1秒的间隔运行它,漂移平均值。+110ms
+11ms
有趣的是,如果我对一个值做同样的事情,平均漂移小于一整毫秒是相当一致的。Timer()
new Timer().schedule(new TimerTask() {
@Override
public void run() {
long drift = (System.currentTimeMillis() - lastTimeStamp - seconds * 1000);
lastTimeStamp = System.currentTimeMillis();
}
}, 0, seconds * 1000);
Linux:不漂移(也不使用Executor,也不使用Timer)
Windows:使用Experidor像疯了一样漂移,与Timer一起漂移
使用 Java8 和 Java11 进行了测试。
有趣的是,如果你假设每秒漂移11毫秒,你每天会得到950400毫秒的漂移,相当于每天。所以它非常一致。15.84 minutes
问题是:为什么?
为什么单线程执行器会发生这种情况,而计时器则不会发生这种情况。
更新1:按照Slaw的评论,我在多个不同的硬件上尝试过。我发现这个问题在任何个人硬件上都没有表现出来。只在公司一个。在公司硬件上,它也体现在Win10上,尽管要少一个数量级。