System.currentTimeMillis vs System.nanoTime

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

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

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

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

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

Если вы ищете исключительно точные измерения прошедшего времени , используйте 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 () для получения дополнительной информации.

Потокобезопасность

Поскольку никто не упомянул об этом …

Не безопасно

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

Безопасно

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

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


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

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

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

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

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

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

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

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

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

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

Да, если требуется такая точность, используйте System.nanoTime() , но имейте в 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)); } } 

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

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

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

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

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

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

О методе nanoTime:

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

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

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

Давайте будем гением компьютера.