Medir o tempo decorrido em Java
1. Visão geral
Neste artigo, vamos dar uma olhada em como medir o tempo decorrido em Java. While this may sound easy, there’re a few pitfalls that we must be aware of.
Exploraremos classes Java padrão e pacotes externos que fornecem funcionalidade para medir o tempo decorrido.
2. Medições Simples
2.1. currentTimeMillis()
Quando encontramos um requisito para medir o tempo decorrido em Java, podemos tentar fazer o seguinte:
long start = System.currentTimeMillis();
// ...
long finish = System.currentTimeMillis();
long timeElapsed = finish - start;
Se olharmos para o código, faz todo o sentido. Recebemos um registro de data e hora no início e outro registro de data e hora quando o código terminou. O tempo decorrido é a diferença entre esses dois valores.
No entanto, o horário do relógio de paredethe result may and will be inaccurate as System.currentTimeMillis() measures wall-clock time. pode mudar por muitos motivos, por exemplo, alterar a hora do sistema pode afetar os resultados ou um salto de segundo interromperá o resultado.
2.2. nanoTime()
Outro método na classejava.lang.System énanoTime(). Se olharmos paraJava documentation, encontraremos a seguinte declaração:
“Este método só pode ser usado para medir o tempo decorrido e não está relacionado a nenhuma outra noção de sistema ou tempo de parede.”
Vamos usar:
long start = System.nanoTime();
// ...
long finish = System.nanoTime();
long timeElapsed = finish - start;
O código é basicamente o mesmo de antes. A única diferença é o método usado para obter carimbos de data / hora -nanoTime() em vez decurrentTimeMillis().
Notemos também quenanoTime(), obviamente, retorna o tempo em nanossegundos. Portanto, se o tempo decorrido for medido em uma unidade de tempo diferente, devemos convertê-lo de acordo.
Por exemplo, para converter em milissegundos, devemos dividir o resultado em nanossegundos por 1.000.000.
Outra armadilha comnanoTime() é queeven though it provides nanosecond precision, it doesn’t guarantee nanosecond resolution (ou seja, com que frequência o valor é atualizado).
No entanto, isso garante que a resolução será pelo menos tão boa quanto a decurrentTimeMillis().
3. Java 8
Se estivermos usando Java 8 - podemos tentar as novas classesjava.time.Instantejava.time.Duration. Ambos são imutáveis, thread-safe e usam sua própria escala de tempo, oJava Time-Scale,, assim como todas as classes dentro da nova APIjava.time.
3.1. Escala de tempo Java
A maneira tradicional de medir o tempo é dividir um dia em 24 horas de 60 minutos de 60 segundos, o que dá 86.400 segundos por dia. No entanto, os dias solares nem sempre são igualmente longos.
A escala de tempo UTC permite que um dia tenha 86,399 ou 86,401 segundos SI. Um segundo SI é um "segundo internacional padrão" científico e é definido por períodos de radiação do átomo de césio 133). Isso é necessário para manter o dia alinhado ao sol.
The Java Time-Scale divides each calendar day into exactly 86.400 subdivisions, known as seconds. Não há segundos bissextos.
3.2. ClasseInstant
A classeInstant representa um instante na linha do tempo. Basicamente, é um carimbo de data / hora numérico desde a época Java padrão de1970-01-01T00:00:00Z.
Para obter o carimbo de data / hora atual, podemos usar o método estáticoInstant.now(). Este método permite passar um parâmetro opcionalClock. Se omitido, ele usa o relógio do sistema no fuso horário padrão.
We can store start and finish times in two variables, as in previous examples. Em seguida, podemos calcular o tempo decorrido entre os dois instantes.
Além disso, podemos usar a classeDuration e seu métodobetween() para obter a duração entre dois objetosInstant. Finalmente, precisamos converterDuration em milissegundos:
Instant start = Instant.now();
// CODE HERE
Instant finish = Instant.now();
long timeElapsed = Duration.between(start, finish).toMillis();
4. StopWatch
Passando para as bibliotecas, o Apache Commons Lang fornece a classeStopWatch que pode ser usada para medir o tempo decorrido.
4.1. Dependência do Maven
Podemos obter a versão mais recente atualizando o pom.xml:
org.apache.commons
commons-lang3
3.7
A versão mais recente da dependência pode ser verificadahere.
4.2. Medindo o tempo decorrido comStopWatch
Primeiro de tudo, precisamos obter uma instância da classe e, em seguida, podemos simplesmente medir o tempo decorrido:
StopWatch watch = new StopWatch();
watch.start();
Assim que tivermos um relógio em execução, podemos executar o código que desejamos avaliar e, no final, simplesmente chamar o métodostop(). Finalmente, para obter o resultado real, chamamosgetTime():
watch.stop();
System.out.println("Time Elapsed: " + watch.getTime()); // Prints: Time Elapsed: 2501
StopWatch has a few additional helper methods that we can use in order to pause or resume our measurement. Isso pode ser útil se precisarmos tornar nosso benchmark mais complexo.
Finalmente, vamos notar que a classe não é segura para thread.
5. Conclusão
Existem várias maneiras de medir o tempo em Java. Cobrimos uma maneira muito "tradicional" (e imprecisa) usandocurrentTimeMillis(). Além disso, verificamosStopWatch do Apache Common e analisamos as novas classes disponíveis no Java 8.
No geral, para medições simples e corretas do tempo decorrido, o métodonanoTime() é suficiente. Também é mais curto digitar do quecurrentTimeMillis().
Vamos notar, entretanto, que para um benchmarking adequado, em vez de medir o tempo manualmente, podemos usar uma estrutura como o Java Microbenchmark Harness (JMH) Este tópico vai além do escopo deste artigo, mas exploramosit here.
Finalmente, como sempre, o código usado durante a discussão pode ser encontradoover on GitHub.