2016-05-24 3 views
5

Я пытаюсь измерить продолжительность некоторого периода как с System.nanoTime(), так и с System.currentTimeMillis(). И чем дольше будет период, тем больше разница получается из двух измерений.nanoTime и currentTimeMillis имеют разную скорость на Mac OS

Вот небольшой фрагмент кода, демонстрирующий проблему:

public class TimeTest { 

    public static void main(String[] args) throws Exception { 
     long startNanos = System.nanoTime(); 
     long startMillis = System.currentTimeMillis(); 

     while (true) { 
      long nowNanos = System.nanoTime(); 
      long nowMillis = System.currentTimeMillis(); 

      System.out.println((nowMillis - startMillis) - (nowNanos - startNanos)/1000000); 

      Thread.sleep(100); 
     } 
    } 
} 

При работе на Mac OS с JDK 1.8.0_74 существует четкая тенденция, что уменьшение значений примерно 2 мс в минуту. То есть сначала я вижу только 0 и 1, но через 10 минут есть значения около -20.

мне удалось наблюдать такое поведение только на макинтош с jdk8, не мог воспроизвести его на Linux и на окнах и с JDK 7 и 8.

Итак, вопрос: кто лжет? Я знаю, что для измерения продолжительности следует использовать nanoTime(). Но в этом случае я не уверен, что это правда.

Может кто-нибудь уточнить эту тему?

+0

Я вижу аналогичную вещь, происходящую на Windows 7 x64 с Java 8. – resueman

ответ

0

Если вы используете NTP, скорее всего, ваш текущийTimeMillis исправляется, поэтому он, скорее всего, будет прав. NanoTime() основан на тактовых частотах/тактовой частоте. Если эта частота немного отключена, то она мер вы увидите постоянный дрейф. Это не должно основываться на версии Java, а скорее на ОС и аппаратных средствах.

+3

Запуск на том же аппаратном обеспечении с помощью java 7 не дает этого дрейфа. Я думаю, что даже нашел объяснение в источниках jdk. http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/f96d42d605e1/src/os/bsd/vm/os_bsd.cpp os :: javaTimeNanos определяется дважды в строках 1022 и 1048. Если 1022 , тогда появляется дрейф. –

+0

Сообщение об ошибке для HotSpot? :) – Nikem

0

И врут :)

Время не может быть измерено с абсолютной точностью. У каждого таймера на вашем компьютере всегда будет небольшой дрейф. Поскольку currentTimeMillis и nanoTime могут исходить из разных таймеров, совершенно естественно, что вы наблюдаете дрейф между ними. Дрейф может даже варьироваться от в зависимости от состояния вашего компьютера (например, рабочая нагрузка на машину может изменить ее температуру и, в свою очередь, вызывать небольшое изменение генератора тактовых импульсов. Эти эффекты небольшие, но всегда они всегда).

В тех случаях, когда, как представляется, нет дрейфа, оба currentTimeMillis и nanoTime либо управляются одним и тем же аппаратным таймером, либо есть коррекция механизма при работе либо в ОС, либо в виртуальной машине.

+0

Я понимаю, что мы не можем измерить время с абсолютной точностью. Но 2 мс каждую минуту составляют почти 3 секунды в день, что кажется слишком большим. Более того, у меня есть доказательства того, что существует способ устранить дрейф, потому что его нет в jdk7. Интересно, было ли это изменение в jdk преднамеренным и является ли оно известной проблемой, потому что оно на 100% воспроизводимо и на других машинах. –

+0

Существует очень простой способ устранения дрейфа: используйте тот же источник таймера для обоих. Недостатком является то, что либо гранулярность nanoTime тогда грубая, либо currentTimeMillis основана на высокочастотном источнике с обычно более высоким дрейфом. Я имею в виду: абсолютный дрейф - это * нормальный * феномен, а относительный дрейф - естественное следствие независимых таймеров. Вполне возможно, что произошли изменения между JRE, чтобы * улучшить * либо детализацию, либо * уменьшить * дрейф, которые вызывают разницу. Не видеть * относительный * дрейф в JRE7 не означает, что это была * лучше * реализация. – Durandal

Смежные вопросы