2010-06-05 32 views
39

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#currentTimeMillis() dice:¿System.currentTimeMillis siempre devolverá un valor> = llamadas anteriores?

devuelve la hora actual en milisegundos. Tenga en cuenta que si bien la unidad de tiempo del valor de retorno es un milisegundo, la granularidad del valor depende del sistema operativo subyacente y puede ser mayor. Por ejemplo, muchos sistemas operativos miden el tiempo en unidades de decenas de milisegundos.

No está claro para mí si se me garantiza que este código siempre imprimirá cada vez mayor (o el mismo) números.

while (1) { 
    System.out.println(System.currentTimeMillis()); 
} 
+0

Por favor, considere citar un enlace más reciente. – trashgod

+4

FYI - la manera precisa de hacer esta pregunta es si 'currentTimeMillis' es * monotonic *. –

+2

Técnicamente, es monótonamente creciente. Las funciones monótonas pueden aumentar o disminuir. –

Respuesta

45

La respuesta corta es no, es System.currentTimeMillis() no monótona. Se basa en el tiempo del sistema y, por lo tanto, puede estar sujeto a variaciones en cualquier dirección (hacia adelante o hacia atrás) en el caso de los ajustes del reloj (por ejemplo, a través del NTP).

System.nanoTime() es monótona, si y sólo si la plataforma subyacente soporta CLOCK_MONOTONIC - ver los comentarios sobre Java bug report 6458294 para una buena valoración crítica en algunas circunstancias en las que esto es/no es cierto.

(Y, como anécdota adicional, personalmente he observado (varias veces) System.currentTimeMillis() ejecutar 'hacia atrás', en ausencia de ajustes de reloj, a través de hilos, es decir, una llamada a ese método en un hilo devolvió una menor valor que una llamada en otro hilo, aunque ocurrió cronológicamente después en "tiempo real")

Si necesita una fuente monotónica, System.nanoTime() en una plataforma que soporte la monotonía es su mejor opción.

+0

+1 Informativo. ¿Podría explicar cómo "observó personalmente" 'currentTimeMillis()' para ejecutar hacia atrás? Esto parece un negocio bastante complicado, y Heisenberg viene a la mente. ¿Has sincronizado tus hilos de alguna manera? ¿Y aún podría observar el tiempo corriendo hacia atrás? –

+2

La versión simple es que tuvimos algunos trabajos de temporización que almacenaron 'long start = System.currentTimeMillis()', y luego dispararon otro hilo para hacer el trabajo, que a su vez hizo 'long end = System.currentTimeMillis()' al final , y restó los dos. Esta diferencia fue (no poco común) negativa en el caso de trabajos de muy corta duración. Esto me confundió hasta que investigué un poco y busqué el código. :) – Cowan

+0

Entonces el hilo # 1 hizo 'long startInCallingThread = Sys.cTM()' y pasó ese valor al hilo # 2, que obtendría valores negativos para 'Sys.cTM() - startInCallingThread'? Interesante. ¿Quizás lo estaba ejecutando en una máquina virtual? Y por * ausencia de ajustes de reloj *, ¿se refiere solo a los ajustes manuales o esto también incluiría ajustes automáticos, como los causados ​​por un daemon ntp? –

8

No podía ser garantizada a ser cada vez mayor, basado en el hecho de que el usuario podría potencialmente cambiar la hora del sistema entre las llamadas.

Además de eso, debe seguir aumentando ya que representa milisegundos desde la época. Si fuera un "tiempo de pared" normal, tendría que preocuparse por los cambios de hora en el día bisiesto o en el cambio de horario de verano.

+1

De hecho, se garantiza que es periódico. Aproximadamente cada 292,277,020 años, imprimirá un número extremadamente grande seguido de un número extremadamente pequeño. – emory

1

@Mark Rushakoff tiene razón; nanoTime() puede ser un poco más confiable.

Adición: tenga en cuenta estos caveats, citado por @Steven Schlansker.

+2

Tenga esto en cuenta: http://stackoverflow.com/questions/510462/is-system-nanotime-completely-useless –

+0

@Steven Schlansker: Gracias, buena referencia. – trashgod

11

No, no siempre será> = todas las llamadas anteriores.

  • Puede que no aumentará cada vez que si se llama varias veces en rápida sucesión desde el mismo hilo (sé que esto es parte de la => =, pero el comportamiento a menudo sorprende a la gente).

  • Si lo llama varias veces en sucesión rápida desde varios subprocesos, podría hacer cualquier cantidad de cosas: podría ir un poco atrás en el tiempo entre subprocesos por una cantidad muy pequeña, dependiendo de la implementación y la posibilidad aleatoria.

  • Lo que es más grave, el valor puede retroceder en el tiempo en una gran cantidad si el usuario (raro) o una sincronización NTP (potencialmente común) ajusta el reloj del sistema.

7

Si quiere un valor que aumenta de forma monótona, puede hacer algo como.

public enum Time { 
    ; 
    private static long lastTime; 
    public synchronized static long increasingTimeMillis() { 
     long now = System.currentTimeMillis(); 
     if (now > lastTime) 
      return lastTime = now; 
     return ++lastTime; 
    } 
} 

Mientras se llama a este menos de un millar de veces por segundo, aumentando su tiempo no irá a la deriva demasiado lejos del tiempo real, pero será único. (Esto puede funcionar, incluso si reinicia su aplicación)

Cuestiones relacionadas