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