У меня есть служба Java, работающая в Windows 7, которая запускается один раз в день на SingleThreadScheduledExecutor
. Я никогда не давал это много, хотя это и не критично, но недавно посмотрел на цифры и увидел, что сервис дрейфовал примерно 15 минут в день, что звучит слишком много, так что откопал.
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
long drift = (System.currentTimeMillis() - lastTimeStamp - seconds * 1000);
lastTimeStamp = System.currentTimeMillis();
}, 0, 10, TimeUnit.SECONDS);
Этот метод довольно последовательно дрейфует +110ms
за каждые 10 секунд. Если я запускаю его с интервалом в 1 секунду, дрейф усредняется +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: с Executor сходит с ума, а с Timer - нет
Протестировано с Java8 и Java11.
Интересно, что если вы допустите дрейф 11 мс в секунду, вы получите дрейф 950400 мс в день, что составляет 15.84 minutes
в день. Так что это довольно последовательно.
Вопрос в том, почему?
Почему это происходит с SingleThreadExecutor, но не с таймером.
Обновление 1: после комментария Slaw я пробовал на нескольких разных аппаратных средствах. Я обнаружил, что эта проблема не проявляется ни на одном персональном оборудовании. Только на компанию одну. На оборудовании компании это также проявляется на Win10, хотя на порядок меньше.