"System.currentTimeMillis ()" è corretto in più processi?
Abbiamo una situazione in cui un processo master scrive su un registro.
Quindi genera più processi di lavoro che scrivono nei propri log. (Volevo che i lavoratori accedessero al master, ma per qualche motivo c'era resistenza a questa idea.)
Quello che voglio sapere è, posso fidarmi che i timestamp che finiscono nei file multipli siano coerenti tra loro? cioè, se unisco i file di log in un unico file ordinato per istante, l'ordine degli eventi sarà vero? Su tutti i possibili sistemi operativi?
Il motivo per cui lo chiedo è che ho una strana situazione in cui sembra che un processo di lavoro abbia registrato un errore due secondi dopo che il master ha segnalato che il lavoratore ha avuto un errore. È come se il maestro fosse in grado di vedere nel futuro. (Immagino che il maestro sia anche un signore del tempo, ma uh ...)
Risposte
La chiamata a System.currentTimeMillis, e la sua sostituzione moderna Instant.now, catturano entrambi il momento corrente come riportato dal sistema operativo host e dall'hardware dell'orologio del computer sottostante. Javadoc e il codice sorgente promettono un orologio "basato sul miglior orologio di sistema disponibile".
Quindi no, non ci dovrebbero essere salti nel futuro . Ogni volta che chiami uno di questi metodi, catturi il momento attuale.
Tuttavia, potresti vedere l'illusione di saltare nel futuro . Ciò può accadere per questi motivi:
- pianificazione dei thread
- ripristino dell'orologio
- orologio falso
Pianificazione dei thread
Questa illusione può verificarsi a causa di ciò che accade dopo che il momento attuale è stato catturato. La frazione di secondo dopo aver catturato il momento corrente, l'esecuzione di quel thread può essere sospesa. Qualche altro thread potrebbe quindi catturare un momento successivo, continuare a segnalare quel momento. Alla fine, quel primo thread riprende e riporta il suo momento catturato in precedenza, ma nota come la segnalazione di quel momento avviene in seguito.
Prendi questo codice di esempio.
package work.basil.example;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TellTime
{
public static void main ( String[] args )
{
TellTime app = new TellTime();
app.demo();
}
private void demo ( )
{
ExecutorService executorService = Executors.newCachedThreadPool();
int countThreads = 15;
List < Callable < Object > > tasks = new ArrayList <>( countThreads );
for ( int i = 0 ; i < countThreads ; i++ )
{
Runnable tellTimeRunnable = ( ) -> System.out.println( Instant.now() );
tasks.add( Executors.callable( tellTimeRunnable ) );
}
try
{
List < Future < Object > > list = executorService.invokeAll( tasks );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
}
La prima volta che ho eseguito quel codice, ho riscontrato un tale salto nelle ultime due righe di output. La quarta riga mostra un momento prima della terza. La quinta riga mostra un momento ancora prima.
2020-11-23T01:07:34.305318Z
2020-11-23T01:07:34.305569Z
2020-11-23T01:07:34.305770Z
2020-11-23T01:07:34.305746Z
2020-11-23T01:07:34.305434Z
Nel mio caso qui, le chiamate a System.out.printlnsono state ritardate nella loro esecuzione, quindi alcuni momenti precedenti sono stati riportati in seguito. Allo stesso modo, sospetto che nel tuo caso, l'atto di registrare i tuoi momenti catturati abbia comportato vari ritardi in modo che alcuni momenti precedenti siano stati registrati in seguito.
Ripristino dell'orologio
Come sottolinea Stephen C nei commenti di seguito , i computer sono spesso configurati per regolare automaticamente l'orologio hardware in base alle informazioni di un server orario. Gli orologi hardware di molti computer sono meno precisi di quanto potresti immaginare. Quindi l'orologio del computer host potrebbe essere reimpostato su un'ora precedente o successiva per correggere la deriva del rilevamento del tempo.
Tieni presente che alcuni computer ripristinano il loro orologio a un punto di riferimento dell'epoca come 1970-01-01 00: 00Z quando vengono avviati con una batteria / condensatore difettoso o esaurito che supporta l'orologio hardware. Quel momento di riferimento dell'epoca può essere riportato come il momento corrente fino a quando il computer non ha la possibilità di effettuare il check-in con il server dell'ora.
Oppure un essere umano potrebbe regolare manualmente la data e l'ora correnti dell'orologio del computer. :-(
Il tuo codice potrebbe catturare il momento corrente su entrambi i lati di questa regolazione dell'orologio. Ora può sembrare che un evento successivo si sia verificato prima.
Orologio falso
In java.time , chiamate come l' Instant.nowaccesso Clockall'implementazione attualmente assegnata . Con "attualmente assegnato", mi riferisco al fatto che in java.time , l' Clockoggetto predefinito può essere sovrascritto. Di solito sarebbe solo a scopo di test. Vari Clockoggetti possono segnalare un momento fisso , un momento spostato o possono segnalare con una cadenza alterata .
Quindi tieni presente che un alternativo Clockpuò volutamente indicare un orario diverso, se il tuo codice di test ha specificato un Clockoggetto alternativo . Per impostazione predefinita, tuttavia, ottieni sempre il momento corrente nel momento in cui viene eseguita la chiamata al metodo.
Conclusione
C'è un'implicazione importante qui: il monitoraggio del tempo non può essere completamente attendibile . Il momento corrente potrebbe essere catturato in modo errato e la segnalazione dei momenti catturati potrebbe essere fuori ordine.
Quindi durante il debug o le indagini, tieni sempre questo pensiero nascosto nella parte posteriore della tua mente: i timestamp e il loro ordine potrebbero non dirti tutta la verità. Alla fine non puoi sapere con certezza al 100% cosa è successo e quando.