В целях диагностики я хочу иметь возможность обнаруживать изменения в системных часах времени в долго работающем серверном приложении.Поскольку System.currentTimeMillis()
основано на времени настенных часов, а System.nanoTime()
основано на системном таймере, который не зависит (*) от времени настенных часов, я подумал, что могу использовать изменения разности между этими значениями для обнаружения изменений системного времени.
Я написал приложение для быстрого тестирования, чтобы увидеть, насколько стабильна разница между этими значениями, и, к моему удивлению, значения сразу меняются на уровне нескольких миллисекунд в секунду.Несколько раз я видел гораздо более быстрые расхождения.Это на 64-битном рабочем столе Win7 с Java 6. Я не пробовал эту тестовую программу ниже под Linux (или Solaris или MacOS), чтобы увидеть, как она работает.Для некоторых прогонов этого приложения расхождение положительное, для некоторых прогонов оно отрицательное.Похоже, это зависит от того, что еще делает рабочий стол, но трудно сказать.
public class TimeTest {
private static final int ONE_MILLION = 1000000;
private static final int HALF_MILLION = 499999;
public static void main(String[] args) {
long start = System.nanoTime();
long base = System.currentTimeMillis() - (start / ONE_MILLION);
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Don't care if we're interrupted
}
long now = System.nanoTime();
long drift = System.currentTimeMillis() - (now / ONE_MILLION) - base;
long interval = (now - start + HALF_MILLION) / ONE_MILLION;
System.out.println("Clock drift " + drift + " ms after " + interval
+ " ms = " + (drift * 1000 / interval) + " ms/s");
}
}
}
Неточности со временем Thread.sleep()
, а также прерывания должны быть совершенно не связаны с дрейфом таймера.
Оба этих «системных» вызова Java предназначены для использования в качестве измерения - один для измерения разницы во времени настенных часов, а другой - для измерения абсолютных интервалов, поэтому, когда часы реального времени не меняются,эти значения должны меняться очень близко к той же скорости, верно?Это ошибка или слабость или сбой в Java?Есть ли в ОС или оборудовании что-то, что мешает Java быть более точным?
Я полностью ожидаю некоторого дрейфа и дрожания (**) между этими независимыми измерениями, но я ожидал гораздо меньше минуты в день дрейфа.,1 мс в секунду дрейфа, если он монотонный, это почти 90 секунд!Мой наблюдаемый дрейф в худшем случае был, возможно, в десять раз большеКаждый раз, когда я запускаю эту программу, я вижу дрейф в самом первом измерении.До сих пор я не запускал программу более 30 минут.
Я ожидаю увидеть небольшую случайность в напечатанных значениях из-за дрожания, но почти во всех запусках программы я вижу устойчивый ростразницы, часто до 3 мсек в секунду при увеличении и в пару раз гораздо больше.
Есть ли в любой версии Windows механизм, аналогичный Linux, который регулирует тактовую частоту системы, чтобы медленно приводитьвремя суток синхронизируется с внешним источником часов?Повлияет ли такая вещь на оба таймера или только на таймер настенных часов?
(*) Я понимаю, что на некоторых архитектурах System.nanoTime()
будет по необходимости использовать тот же механизм, что и System.currentTimeMillis()
.Я также считаю, что справедливо предположить, что любой современный сервер Windows не имеет такой аппаратной архитектуры.Это неверное предположение?
(**) Конечно, System.currentTimeMillis()
обычно имеет гораздо больший джиттер, чем System.nanoTime()
, поскольку его гранулярность не составляет 1 мсек в большинстве систем.