System.currentTimeMillis vs System.nanoTime

Точность Vs. Точность

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

Я читал, что между различными операционными системами существуют серьезные проблемы с разрешением по времени (а именно, что Mac/Linux имеет разрешение почти 1 мс, а Windows имеет разрешение 50 мс?). Я использую только приложения на окнах, а разрешение 50 мс кажется довольно неточным.

Есть ли лучшие варианты, чем два перечисленных мной?

Любые предложения/комментарии?

Ответ 1

Если вы ищете исключительно точные измерения прошедшего времени, используйте System.nanoTime(). System.currentTimeMillis() даст вам самое точное истекшее время в миллисекундах с эпохи, но System.nanoTime() дает вам наносекундное точное время относительно некоторой произвольной точки.

Из документации Java:

public static long nanoTime()

Возвращает текущее значение наиболее точного доступного системного таймера в наносекундах.

Этот метод можно использовать только для измерения прошедшего времени и не имеет отношения к какому-либо другому понятию системного или настенного времени. Возвращаемое значение представляет собой наносекунды с некоторого фиксированного, но произвольного времени (возможно, в будущем, поэтому значения могут быть отрицательными). Этот метод обеспечивает наносекундную точность, но не обязательно наносекундную точность. Никаких гарантий относительно того, как часто меняются ценности, не делается. Различия в последовательных вызовах, которые охватывают более 292 лет (2 63 наносекунды), не будут точно вычислять прошедшее время из-за численного переполнения.

Например, чтобы определить, сколько времени требуется выполнить код:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

См. Также: JavaDoc System.nanoTime() и JavaDoc System.currentTimeMillis() для получения дополнительной информации.

Ответ 2

Так как никто другой не упомянул об этом...

Не безопасно сравнивать результаты вызовов System.nanoTime() между разными потоками. Даже если события потоков происходят в предсказуемом порядке, разница в наносекундах может быть положительной или отрицательной.

System.currentTimeMillis() безопасен для использования между потоками.

Ответ 3

Обновление Arkadiy: я наблюдал более правильное поведение System.currentTimeMillis() в Windows 7 в Oracle Java 8. Время было возвращено с точностью 1 миллисекунда, Исходный код в OpenJDK не изменился, поэтому я не знаю, что вызывает лучшее поведение.


Дэвид Холмс из Sun опубликовал статью в блоге пару лет назад, в которой очень подробно рассматривается API-интерфейсы Java (в частности System.currentTimeMillis() и System.nanoTime()), когда вы захотите использовать, какие и как они работают внутри.

Внутри виртуальной машины Hotspot: часы, таймеры и события планирования - часть я - Windows

Один очень интересный аспект таймера, используемый Java для Windows для API-интерфейсов с параметром ожидания по времени, заключается в том, что разрешение таймера может меняться в зависимости от того, какие другие вызовы API могли быть сделаны - в широком масштабе (не только в особый процесс). Он показывает пример, где использование Thread.sleep() приведет к изменению этого разрешения.

Ответ 4

System.nanoTime() не поддерживается в старых JVM. Если это вызывает беспокойство, придерживайтесь currentTimeMillis

Что касается точности, вы почти правы. На некоторых компьютерах Windows currentTimeMillis() имеет разрешение около 10 мс (не 50 мс). Я не уверен, почему, но некоторые машины Windows настолько же точны, как и машины Linux.

Я использовал GAGETimer в прошлом с умеренным успехом.

Ответ 5

Как говорили другие, currentTimeMillis - это время часов, которое изменяется из-за перехода на летнее время, пользователи меняют настройки времени, прыжки секунд и синхронизацию времени в Интернете. Если ваше приложение зависит от монотонно увеличивающихся истекших значений времени, вы можете предпочесть nanoTime.

Вы можете подумать, что игроки не будут возиться с настройками времени во время игры, и, возможно, вы будете правы. Но не стоит недооценивать сбой из-за синхронизации времени в Интернете или, возможно, с удаленными настольными пользователями. API nanoTime невосприимчив к такого рода нарушениям.

Если вы хотите использовать часы, но избегайте разрывов из-за синхронизации времени в Интернете, вы можете подумать о клиенте NTP, таком как Meinberg, который "настраивает" тактовую частоту на нуль, вместо того, чтобы просто периодически перезапускать часы.

Я говорю из личного опыта. В приложении погоды, которое я разработал, я получал случайно возникающие всплески скорости ветра. Мне потребовалось некоторое время, чтобы понять, что моя временная база была нарушена поведением часового времени на обычном ПК. Все мои проблемы исчезли, когда я начал использовать nanoTime. Консистенция (монотонность) была более важной для моего приложения, чем необработанная точность или абсолютная точность.

Ответ 6

Да, если требуется такая точность, используйте System.nanoTime(), но имейте в виду, что вам требуется Java 5+ JVM.

В моих системах XP я вижу системное время как минимум 100 микросекунд 278 наносекунд, используя следующий код:

private void test() {
    System.out.println("currentTimeMillis: "+System.currentTimeMillis());
    System.out.println("nanoTime         : "+System.nanoTime());
    System.out.println();

    testNano(false);                                                            // to sync with currentTimeMillis() timer tick
    for(int xa=0; xa<10; xa++) {
        testNano(true);
        }
    }

private void testNano(boolean shw) {
    long strMS=System.currentTimeMillis();
    long strNS=System.nanoTime();
    long curMS;
    while((curMS=System.currentTimeMillis()) == strMS) {
        if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)); }
        }
    if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)+", Milli: "+(curMS-strMS)); }
    }

Ответ 7

У меня был хороший опыт работы с nanotime. Он обеспечивает время настенных часов как две длинные (секунды с эпохи и наносекунды в течение этой секунды), используя библиотеку JNI. Он доступен с частью JNI, предварительно скомпилированной как для Windows, так и для Linux.

Ответ 8

Для игровой графики и плавного обновления положения используйте System.nanoTime(), а не System.currentTimeMillis(). Я переключился с currentTimeMillis() на nanoTime() в игру и получил значительное визуальное улучшение плавности движения.

Хотя одна миллисекунда может показаться, что она уже должна быть точной, визуально это не так. Факторы nanoTime() могут улучшиться:

  • точное позиционирование пикселей ниже разрешения настенных часов
  • способность к сглаживанию между пикселями, если вы хотите
  • Неточность настенных часов Windows
  • джиттер часов (несогласованность того, когда настенные часы фактически гаснут вперед)

Как показывают другие ответы, nanoTime действительно имеет стоимость исполнения, если вызывается многократно - лучше было бы назвать его только один раз за кадр и использовать одно и то же значение для вычисления всего кадра.

Ответ 9

System.currentTimeMillis() небезопасно для прошедшего времени, потому что этот метод чувствителен к системным изменениям в режиме реального времени в системе. Вы должны использовать System.nanoTime. Пожалуйста, обратитесь к справочной системе Java:

О методе nanoTime:

. Этот метод обеспечивает наносекундную точность, но не обязательно наносекундное разрешение (то есть, как часто изменяется значение) - нет предоставляются гарантии, за исключением того, что разрешение не менее это currentTimeMillis()..

Если вы используете System.currentTimeMillis(), ваше прошедшее время может быть отрицательным (Назад < - в будущее)

Ответ 10

System.currentTimeMillis() не является безопасным для прошедшего времени, потому что этот метод чувствителен к времени sy системы. Вы должны использовать System.nanoTime. Пожалуйста, обратитесь к справочной системе Java:

О методе nanoTime:

. Этот метод обеспечивает наносекундную точность, но не обязательно наносекундное разрешение (то есть, как часто изменяется значение) - нет предоставляются гарантии, за исключением того, что разрешение не менее это currentTimeMillis()..

Если вы используете System.currentTimeMillis(), ваше прошедшее время может быть отрицательным (Назад < - в будущее)

Ответ 11

одна вещь здесь - несогласованность метода nanoTime.it не дает очень согласованных значений для одного и того же ввода. CurrentTimeMillis делает намного лучше с точки зрения производительности и согласованности, а также, хотя и не такой точный, как nanoTime, имеет более низкую предел погрешности и, следовательно, большую точность в его значении. поэтому я предлагаю вам использовать currentTimeMillis