System.currentTimeMillis y System.nanoTime
Precisión vs. Precisión
Lo que me gustaría saber es si debo usar System.currentTimeMillis() o System.nanoTime() al actualizar las posiciones de mis objetos en mi juego. Su cambio de movimiento es directamente proporcional al tiempo transcurrido desde la última llamada y quiero ser lo más preciso posible.
He leído que existen algunos problemas graves de resolución de tiempo entre diferentes sistemas operativos (es decir, ¿Mac/Linux tiene una resolución de casi 1 ms mientras que Windows tiene una resolución de 50 ms?). Principalmente ejecuto mis aplicaciones en Windows y la resolución de 50 ms parece bastante inexacta.
¿Hay mejores opciones que las dos que enumeré?
¿Alguna sugerencia/comentario?
Si solo busca mediciones extremadamente precisas del tiempo transcurrido , utilice System.nanoTime()
. System.currentTimeMillis()
le dará el tiempo transcurrido más preciso posible en milisegundos desde la época, pero System.nanoTime()
le dará un tiempo preciso en nanosegundos, en relación con algún punto arbitrario.
De la documentación de Java:
public static long nanoTime()
Devuelve el valor actual del temporizador del sistema disponible más preciso, en nanosegundos.
Este método sólo se puede utilizar para medir el tiempo transcurrido y no está relacionado con ninguna otra noción de tiempo del sistema o del reloj de pared. El valor devuelto representa nanosegundos desde un tiempo de origen fijo pero arbitrario (quizás en el futuro, por lo que los valores pueden ser negativos). Este método proporciona una precisión de nanosegundos, pero no necesariamente una precisión de nanosegundos. No se ofrecen garantías sobre la frecuencia con la que cambian los valores. Las diferencias en llamadas sucesivas que abarcan más de aproximadamente 292 años (2,63 nanosegundos ) no calcularán con precisión el tiempo transcurrido debido al desbordamiento numérico.
Por ejemplo, para medir cuánto tiempo tarda en ejecutarse un código:
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
Consulte también: JavaDoc System.nanoTime() y JavaDoc System.currentTimeMillis() para obtener más información.
Como nadie más ha mencionado esto...
No es seguro comparar los resultados de System.nanoTime()
las llamadas entre diferentes JVM, cada JVM puede tener un tiempo de "origen" independiente.
System.currentTimeMillis()
devolverá el mismo valor (aproximadamente) entre JVM, porque está vinculado a la hora del reloj de pared del sistema.
Si desea calcular la cantidad de tiempo que ha transcurrido entre dos eventos, como un cronómetro, utilice nanoTime()
; Los cambios en el reloj de pared del sistema son currentTimeMillis()
incorrectos para este caso de uso.
Actualización de Arkadiy : He observado un comportamiento más correcto System.currentTimeMillis()
en Windows 7 en Oracle Java 8. La hora se devolvió con una precisión de 1 milisegundo. El código fuente en OpenJDK no ha cambiado, por lo que no sé qué causa el mejor comportamiento.
David Holmes de Sun publicó un artículo de blog hace un par de años que ofrece una visión muy detallada de las API de temporización de Java (en particular System.currentTimeMillis()
y System.nanoTime()
), cuándo desea utilizar cuáles y cómo funcionan internamente.
Dentro de la máquina virtual Hotspot: relojes, temporizadores y programación de eventos - Parte I - Windows
Un aspecto muy interesante del temporizador utilizado por Java en Windows para las API que tienen un parámetro de espera temporizado es que la resolución del temporizador puede cambiar dependiendo de qué otras llamadas API se hayan realizado: en todo el sistema (no solo en el proceso particular). . Muestra un ejemplo en el que el uso Thread.sleep()
provocará este cambio de resolución.
Como han dicho otros, currentTimeMillis es la hora del reloj, que cambia debido al horario de verano ( no: el horario de verano y la zona horaria no están relacionados con currentTimeMillis, el resto es cierto ), los usuarios cambian la configuración de hora, los segundos intercalares y la sincronización de la hora de Internet. Si su aplicación depende de valores de tiempo transcurrido que aumentan monótonamente, es posible que prefiera nanoTime.
Podrías pensar que los jugadores no jugarán con la configuración del tiempo durante el juego, y tal vez tengas razón. Pero no subestime la interrupción debida a la sincronización de la hora de Internet o quizás a los usuarios de escritorio remoto. La API nanoTime es inmune a este tipo de perturbaciones.
Si desea utilizar la hora del reloj, pero evitar discontinuidades debido a la sincronización de la hora de Internet, podría considerar un cliente NTP como Meinberg, que "sintoniza" la velocidad del reloj para ponerla a cero, en lugar de simplemente restablecer el reloj periódicamente.
Hablo por experiencia personal. En una aplicación meteorológica que desarrollé, obtuve picos de velocidad del viento que ocurrían aleatoriamente. Me tomó un tiempo darme cuenta de que mi base de tiempo estaba siendo interrumpida por el comportamiento del reloj en una PC típica. Todos mis problemas desaparecieron cuando comencé a usar nanoTime. La consistencia (monotonicidad) era más importante para mi aplicación que la precisión bruta o la exactitud absoluta.