example - my icon java
¿Hay alguna implementación de reloj consistente(monotónica) en Java? (2)
Como dice @ the8472, la clave es tener la sincronización de hora en la máquina (donde se ejecuta el jvm) correcta.
Si programa un cliente, puede ser peligroso confiar en los relojes del sistema. Pero para los servidores, existe una solución: es posible que desee considerar el uso de NTP con una configuración estricta.
Aquí , básicamente, explican que el NTP ralentizará el tiempo y no lo hará al revés.
Y esta documentación NTP dice:
A veces, en particular cuando se inicia ntpd por primera vez, el error puede exceder los 128 ms. En ocasiones, esto puede hacer que el reloj se ajuste hacia atrás si la hora local del reloj es más de 128 s en el futuro en relación con el servidor. En algunas aplicaciones, este comportamiento puede ser inaceptable. Si la opción -x está incluida en la línea de comando, el reloj nunca se pasará y solo se usarán las correcciones de giro.
La implementación predeterminada de java.time.Clock se basa en System.currentTimeMillis () . Como se discute, por ejemplo, aquí, ¿ Incremento monótono del tiempo en Java? , no se garantiza que sea monotónico.
Y de hecho, regularmente experimento una situación en la que la hora del sistema se ajusta automáticamente unos segundos al pasado y el reloj de Java también retrocede.
//now() returns 2016-01-13T22:34:05.681Z
order.setCreationTime(Instant.now());
//... something happens, order gets cancelled
//now() returns 2016-01-13T22:34:03.123Z
//which is a few seconds before the former one,
//even though the call was performed later - in any reasonable sense.
//The recorded history of events is obviously inconsistent with the real world.
order.setCancelationTime(Instant.now());
Entonces es imposible realizar cosas sensibles al tiempo, como registrar y analizar el historial de eventos, cuando no se puede confiar en que el tiempo vaya solo en una dirección.
El post mencionado anteriormente dice que System.nanoTime () es monotónico (si el sistema subyacente lo admite). Por lo tanto, si quiero basar mi código en la API java.time, necesitaría un reloj que use nanoTime internamente para garantizar un flujo unidireccional del tiempo. Tal vez algo como esto podría funcionar. ¿O no?
public class MyClock() extends java.time.Clock {
private final long adjustment;
public MyClock() {
long cpuTimeMillis = System.nanoTime()/1000000;
long systemTimeMillis = System.currentTimeMillis();
adjustment = systemTimeMillis - cpuTimeMillis;
}
@Override
public long millis() {
long currentCpuTimeMillis = System.nanoTime()/1000000;
return currentCpuTimeMillis + adjustment;
}
}
Es solo un boceto, no una implementación completa del Reloj. Y supongo que una implementación adecuada también debería realizar el ajuste contra otro Reloj pasado en el constructor, en lugar de hacerlo directamente contra currentTimeMillis ().
O bien, ¿ya existe tal implementación de Reloj monotónica disponible en cualquier lugar? Supongo que debe haber muchas personas que enfrentan el mismo problema.
Conclusión
Gracias por los inspiradores comentarios y respuestas. Hay varios puntos interesantes dispersos en los comentarios, así que los resumiré aquí.
1. Reloj monotónico
En cuanto a mi pregunta original, sí, es posible tener un reloj monotónico que no se vea afectado por el tiempo del sistema saltando hacia atrás. Dicha implementación se puede basar en System.nanoTime () como sugerí anteriormente. Solía haber problemas con este enfoque en el pasado, pero debería funcionar bien en los sistemas modernos de hoy. Este enfoque ya está implementado, por ejemplo, en la biblioteca Time4J , su reloj monotónico se puede convertir fácilmente a java.time.Clock:
Clock clock = TemporalType.CLOCK.from(SystemClock.MONOTONIC);
2. Control apropiado del tiempo del sistema
Es posible configurar la administración de la hora del sistema (ntpd en unix / linux), de modo que la hora del sistema prácticamente nunca retroceda (se ralentiza si es necesario), entonces se puede confiar en que la hora del sistema sea monotónica, y sin reloj La magia es necesaria en Java.
Iré de esta manera, ya que mi aplicación está del lado del servidor y puedo controlar el tiempo. En realidad, experimenté las anomalías en un entorno experimental que me instalé (solo con un conocimiento superficial del dominio), y estaba usando solo el cliente ntpdate (que puede saltar hacia atrás si el tiempo no está sincronizado), en lugar de ntpd (que se puede configurar para que no salte hacia atrás).
3. Usar secuencias en lugar de reloj.
Cuando se necesita rastrear una relación fuerte de lo que sucedió antes de qué, es más seguro dar a los eventos números de serie de una secuencia generada atómicamente y no confiar en el reloj de pared. Se convierte en la única opción una vez que la aplicación se ejecuta en varios nodos (aunque este no es mi caso).
Tenga en cuenta que nanoTime puede aumentar monótonamente pero no se relaciona bien con el tiempo de la pared, por ejemplo, debido a eventos de hibernación, suspensión de VM y cosas similares.
Y si comienza a distribuir cosas entre varios servidores, la sincronización en currentMillis también puede morderle nuevamente debido a la tendencia del reloj.
Tal vez debería considerar controlar la hora del sistema de sus servidores.
O rastree la secuencia relativa de los eventos por separado del momento en que supuestamente se registraron.