Что я хотел бы знать, так это должен ли я использовать System.currentTimeMillis() или System.nanoTime() при обновлении позиций моего объекта в моей игре? Их изменение в движении прямо пропорционально времени, прошедшему с момента последнего вызова, и я хочу быть как можно более точным.
Я читал, что между различными операционными системами существуют некоторые серьезные проблемы с разрешением по времени (а именно, что Mac / Linux имеют разрешение почти в 1 мс, в то время как Windows имеет разрешение в 50 мс ??). Я в основном запускаю свои приложения в Windows, и разрешение 50 мс кажется довольно неточным.
Есть ли варианты лучше, чем два, которые я перечислил?
Есть предложения / комментарии?
Переведено автоматически
Ответ 1
Если вы просто ищете чрезвычайно точные измерения прошедшего времени, используйте System.nanoTime(). System.currentTimeMillis() даст вам максимально точное возможное время в миллисекундах, прошедшее с момента начала эпохи, но System.nanoTime() даст вам время с точностью до наносекунды относительно некоторой произвольной точки.
Из документации Java:
publicstaticlongnanoTime()
Возвращает текущее значение наиболее точного доступного системного таймера в наносекундах.
Этот метод может использоваться только для измерения прошедшего времени и не связан с каким-либо другим понятием системного времени или времени настенных часов. Возвращаемое значение представляет наносекунды с некоторого фиксированного, но произвольного начального времени (возможно, в будущем, поэтому значения могут быть отрицательными). Этот метод обеспечивает наносекундную точность, но не обязательно наносекундную. Не дается никаких гарантий относительно частоты изменения значений. Различия в последовательных вызовах, которые занимают более 292 лет (263 наносекунды), не позволяют точно вычислить прошедшее время из-за числового переполнения.
Например, чтобы измерить, сколько времени требуется для выполнения некоторого кода:
longstartTime= System.nanoTime(); // ... the code being measured ... longestimatedTime= System.nanoTime() - startTime;
Небезопасно сравнивать результаты System.nanoTime() вызовов между разными JVM, каждая JVM может иметь независимое "исходное" время.
System.currentTimeMillis() вернет (приблизительно) одинаковое значение между JVM, потому что оно привязано к времени системных настенных часов.
Если вы хотите вычислить количество времени, прошедшего между двумя событиями, например, по секундомеру, используйте nanoTime(); изменения в системных настенных часах делают currentTimeMillis() некорректным для этого варианта использования.
Ответ 3
Обновление от Аркадия: Я наблюдал более корректное поведение System.currentTimeMillis() в Windows 7 в Oracle Java 8. Время было возвращено с точностью до 1 миллисекунды. Исходный код в OpenJDK не изменился, поэтому я не знаю, что вызывает лучшее поведение.
Дэвид Холмс из Sun пару лет назад опубликовал статью в блоге, в которой очень подробно рассматриваются Java timing API (в частности, System.currentTimeMillis() и System.nanoTime()), когда вы хотели бы что-то использовать и как они работают внутри.
Один очень интересный аспект таймера, используемого Java в Windows для API с параметром timed wait, заключается в том, что разрешение таймера может меняться в зависимости от того, какие другие вызовы API могли быть выполнены - в масштабах всей системы (а не только в конкретном процессе). Он показывает пример, где использование Thread.sleep() вызовет это изменение разрешения.
Ответ 4
Как уже говорили другие, currentTimeMillis - это время на часах, которое меняется в связи с переходом на летнее время (нет: переход на летнее время и часовой пояс не связаны с currentTimeMillis, остальное верно), пользователи меняют настройки времени, високосные секунды и синхронизацию времени в Интернете. Если ваше приложение зависит от монотонно возрастающих значений прошедшего времени, вы можете предпочесть nanoTime.
Вы можете подумать, что игроки не будут возиться с настройками времени во время игры, и, возможно, вы будете правы. Но не стоит недооценивать сбои из-за синхронизации времени в Интернете или, возможно, пользователей удаленных рабочих столов. API nanoTime невосприимчив к такого рода сбоям.
Если вы хотите использовать тактовое время, но избегать перебоев из-за синхронизации времени в Интернете, вы могли бы рассмотреть NTP-клиент, такой как Meinberg, который "настраивает" тактовую частоту на обнуление, вместо того, чтобы просто периодически сбрасывать часы.
Я говорю по личному опыту. В приложении погоды, которое я разработал, я получал случайные скачки скорости ветра. Мне потребовалось некоторое время, чтобы понять, что моя временная база была нарушена поведением часов на обычном ПК. Все мои проблемы исчезли, когда я начал использовать nanoTime. Согласованность (монотонность) была более важна для моего приложения, чем необработанная точность или абсолютная.