Misura il tempo trascorso in Java

1. Panoramica

In questo articolo, daremo un'occhiata a come misurare il tempo trascorso in Java. Anche se questo può sembrare facile, ci sono alcune insidie ​​di cui dobbiamo essere consapevoli.

Esploreremo classi Java standard e pacchetti esterni che forniscono funzionalità per misurare il tempo trascorso.

2. Misurazioni semplici

2.1. currentTimeMillis ()

Quando incontriamo un requisito per misurare il tempo trascorso in Java, possiamo provare a farlo come:

long start = System.currentTimeMillis(); // ... long finish = System.currentTimeMillis(); long timeElapsed = finish - start;

Se guardiamo il codice ha perfettamente senso. Otteniamo un timestamp all'inizio e ne riceviamo un altro al termine del codice. Il tempo trascorso è la differenza tra questi due valori.

Tuttavia, il risultato può e sarà impreciso poiché System.currentTimeMillis () misura l' ora dell'orologio da parete . L'ora dell'orologio da parete può cambiare per molti motivi, ad esempio la modifica dell'ora di sistema può influire sui risultati o un secondo intercalare interromperà il risultato.

2.2. nanoTime ()

Un altro metodo nella classe java.lang.System è nanoTime () . Se guardiamo la documentazione Java, troveremo la seguente dichiarazione:

"Questo metodo può essere utilizzato solo per misurare il tempo trascorso e non è correlato a nessun altro concetto di tempo di sistema o orologio da parete."

Usiamolo:

long start = System.nanoTime(); // ... long finish = System.nanoTime(); long timeElapsed = finish - start;

Il codice è fondamentalmente lo stesso di prima. L'unica differenza è il metodo utilizzato per ottenere i timestamp: nanoTime () invece di currentTimeMillis () .

Notiamo anche che nanoTime () , ovviamente, restituisce il tempo in nanosecondi. Pertanto, se il tempo trascorso è misurato in un'unità di tempo diversa, dobbiamo convertirlo di conseguenza.

Ad esempio, per convertire in millisecondi dobbiamo dividere il risultato in nanosecondi per 1.000.000.

Un'altra trappola con nanoTime () è che, anche se fornisce una precisione al nanosecondo, non garantisce la risoluzione al nanosecondo (ovvero quanto spesso il valore viene aggiornato).

Tuttavia, garantisce che la risoluzione sarà almeno pari a quella di currentTimeMillis () .

3. Java 8

Se stiamo usando Java 8, possiamo provare le nuove classi java.time.Instant e java.time.Duration . Entrambi sono immutabili, thread-safe e utilizzano la propria scala temporale, Java Time-Scale, così come tutte le classi all'interno della nuova API java.time .

3.1. Scala temporale Java

Il modo tradizionale di misurare il tempo è dividere un giorno in 24 ore di 60 minuti di 60 secondi, che danno 86.400 secondi al giorno. Tuttavia, i giorni solari non sono sempre ugualmente lunghi.

La scala temporale UTC in realtà consente a un giorno di avere 86,399 o 86,401 secondi SI. Un secondo SI è un "secondo standard internazionale" scientifico ed è definito dai periodi di radiazione dell'atomo di cesio 133). Questo è necessario per mantenere il giorno allineato con il sole.

La scala temporale di Java divide ogni giorno di calendario in esattamente 86.400 suddivisioni, note come secondi . Non ci sono secondi intercalari.

3.2. Classe istantanea

La classe Instant rappresenta un istante sulla sequenza temporale. Fondamentalmente, è un timestamp numerico dall'epoca standard di Java del 1970-01-01T00: 00: 00Z .

Per ottenere il timestamp corrente, possiamo utilizzare il metodo statico Instant.now () . Questo metodo consente di passare un parametro Clock opzionale . Se omesso, utilizza l'orologio di sistema nel fuso orario predefinito.

Possiamo memorizzare i tempi di inizio e di fine in due variabili, come negli esempi precedenti. Successivamente, possiamo calcolare il tempo trascorso tra entrambi gli istanti.

Possiamo inoltre utilizzare la classe Duration ed è il metodo between () per ottenere la durata tra due oggetti Instant . Infine, dobbiamo convertire la durata in millisecondi:

Instant start = Instant.now(); // CODE HERE Instant finish = Instant.now(); long timeElapsed = Duration.between(start, finish).toMillis();

4. Cronometro

Passando alle librerie, Apache Commons Lang fornisce la classe StopWatch che può essere utilizzata per misurare il tempo trascorso.

4.1. Dipendenza da Maven

Possiamo ottenere l'ultima versione aggiornando il pom.xml:

 org.apache.commons commons-lang3 3.7 

L'ultima versione della dipendenza può essere verificata qui.

4.2. Misurazione del tempo trascorso con il cronometro

Prima di tutto, dobbiamo ottenere un'istanza della classe e quindi possiamo semplicemente misurare il tempo trascorso:

StopWatch watch = new StopWatch(); watch.start();

Una volta che abbiamo un orologio in esecuzione, possiamo eseguire il codice che vogliamo confrontare e quindi, alla fine, chiamiamo semplicemente il metodo stop () . Infine, per ottenere il risultato effettivo, chiamiamo getTime () :

watch.stop(); System.out.println("Time Elapsed: " + watch.getTime()); // Prints: Time Elapsed: 2501

StopWatch ha alcuni metodi di supporto aggiuntivi che possiamo utilizzare per mettere in pausa o riprendere la nostra misurazione. Questo può essere utile se dobbiamo rendere il nostro benchmark più complesso.

Infine, notiamo che la classe non è thread-safe.

5. conclusione

Esistono molti modi per misurare il tempo in Java. Abbiamo coperto un modo molto "tradizionale" (e impreciso) utilizzando currentTimeMillis () . Inoltre, abbiamo controllato StopWatch di Apache Common e abbiamo esaminato le nuove classi disponibili in Java 8.

Nel complesso, per misurazioni semplici e corrette del tempo trascorso, è sufficiente il metodo nanoTime () . È anche più breve da digitare rispetto a currentTimeMillis () .

Notiamo, tuttavia, che per un corretto benchmarking, invece di misurare il tempo manualmente, possiamo utilizzare un framework come Java Microbenchmark Harness (JMH). Questo argomento va oltre lo scopo di questo articolo, ma lo abbiamo esplorato qui.

Infine, come sempre, il codice utilizzato durante la discussione può essere trovato su GitHub.