L'impostazione predefinita java.time.Clock è basata su System.currentTimeMillis(). Come discusso qui ad esempio, Monotonically increasing time in Java?, non è garantito che sia monotonico.Esiste un'implementazione di clock coerente (monotona) in Java?
E in effetti, ho regolarmente una situazione in cui l'ora del sistema viene regolata automaticamente pochi secondi al passato e anche l'orologio java salta indietro.
//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());
E 'quindi impossibile effettuare cose time-sensitive, come la storia di registrazione e analisi caso, quando non si può fare affidamento su tempo andando in una sola direzione.
Il post di cui sopra dice che System.nanoTime() è monotono (se il sistema sottostante lo supporta). Quindi, se voglio basare il mio codice sull'API java.time, mi servirebbe Clock che usi nanoTime internamente per garantire un flusso unidirezionale del tempo. Forse qualcosa del genere funzionerebbe. 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;
}
}
È solo uno schizzo, non un'implementazione completa di Clock. E suppongo che una corretta implementazione dovrebbe anche eseguire la regolazione su un altro Clock passato nel costruttore, piuttosto che direttamente contro il currentTimeMillis().
Oppure, è già disponibile un'implementazione dell'orologio monotona? Direi che ci devono essere state molte persone con lo stesso problema.
Conclusione
Grazie per i commenti ispiratori e risposte. Ci sono diversi punti interessanti sparsi nei commenti, quindi lo riassumerò qui.
1. Monotonic orologio
Per quanto riguarda la mia domanda iniziale, sì, è possibile avere l'orologio monotona che non è influenzata dal tempo del sistema saltando all'indietro. Tale implementazione può essere basata su System.nanoTime() come suggerito sopra. In passato c'erano problemi con questo approccio, ma dovrebbe funzionare bene sui moderni sistemi odierni. Questo approccio è già implementata, ad esempio nella biblioteca Time4J, il loro orologio monotona può essere facilmente convertito in java.time.Clock:
Clock clock = TemporalType.CLOCK.from(SystemClock.MONOTONIC);
2. tempo adeguato sistema di controllo
E 'possibile configurare gestione del tempo di sistema (ntpd in unix/linux), in modo che il tempo di sistema non si arresti praticamente mai (si rallenta se necessario), quindi si può fare affidamento sul fatto che il tempo di sistema è monotonico e non è necessaria la magia dell'orologio in Java .
Vado in questo modo, poiché la mia app è lato server e posso avere il tempo sotto controllo. In realtà, ho sperimentato le anomalie in un ambiente sperimentale che ho installato io stesso (solo con conoscenza superficiale del dominio) e utilizzavo solo il ntpdate client (che può saltare all'indietro se il tempo non è sincronizzato), piuttosto che ntpd (che può essere configurato in modo che non salti indietro).
3. Utilizzando sequenze piuttosto che l'orologio
Quando si ha la necessità di tenere traccia di una forte relazione quello che è successo prima cosa, è più sicuro di dare gli eventi numeri di serie da una sequenza atomicamente generato e non fare affidamento sulla parete orologio. Diventa l'unica opzione una volta che l'applicazione è in esecuzione su diversi nodi (che però non è il mio caso).
Anche se il tempo è una cosa monotona, le date non lo sono. Le date sono una costruzione umana per rappresentare il tempo. Se hai bisogno di qualcosa per rappresentare il tempo puramente, forse potresti usare una sequenza di database o qualsiasi altra informazione affidabile. – Leo
nanoTime potrebbe non fare ciò che ti serve. http://www.principiaprogramatica.com/?p=16 – Bill
Potresti essere in grado di studiare la fonte della mia [implementazione dell'orologio monotonico] (http://time4j.net/javadoc-en/net/time4j/SystemClock.html #MONOTONIC) per trasferire alcune idee sul tuo orologio basato su java.time. Fonte: vedi: https://github.com/MenoData/Time4J/blob/master/core/src/main/java/net/time4j/SystemClock.java –