Измерение прошедшего времени в Java

Измерение прошедшего времени в Java

1. обзор

В этой статье мы рассмотрим, как измерить прошедшее время в Java. While this may sound easy, there’re a few pitfalls that we must be aware of.с

Мы рассмотрим стандартные классы Java и внешние пакеты, которые предоставляют функции для измерения затраченного времени.

2. Простые измерения

2.1. currentTimeMillis()с

Когда мы сталкиваемся с требованием измерить прошедшее время в Java, мы можем попытаться сделать это следующим образом:

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

Если мы посмотрим на код, это имеет смысл. Мы получаем метку времени в начале и получаем другую метку времени, когда код закончен. Прошедшее время - это разница между этими двумя значениями.

Однако время на настенных часахthe result may and will be inaccurate as System.currentTimeMillis() measures wall-clock time. может измениться по многим причинам, например, изменение системного времени может повлиять на результаты, или дополнительная секунда нарушит результат.

2.2. nanoTime()с

Другой метод в классеjava.lang.System -nanoTime(). Если мы посмотрим наJava documentation, мы найдем следующее утверждение:

«Этот метод может использоваться только для измерения прошедшего времени и не связан ни с каким другим понятием системного времени или времени настенных часов».

Давайте использовать это:

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

Код в основном такой же, как и раньше. Единственное отличие - это метод, используемый для получения меток времени -nanoTime() вместоcurrentTimeMillis().

Также отметим, чтоnanoTime(), очевидно, возвращает время в наносекундах. Поэтому, если прошедшее время измеряется в другой единице времени, мы должны соответствующим образом преобразовать его.

Например, чтобы преобразовать в миллисекунды, мы должны разделить результат в наносекундах на 1.000.000.

Другая ловушка сnanoTime() заключается в том, чтоeven though it provides nanosecond precision, it doesn’t guarantee nanosecond resolution (т.е. как часто значение обновляется).

Однако это гарантирует, что разрешение будет не ниже, чем уcurrentTimeMillis().

3. Java 8

Если мы используем Java 8, мы можем попробовать новые классыjava.time.Instant иjava.time.Duration. Оба являются неизменяемыми, поточно-ориентированными и используют собственную шкалу времени,Java Time-Scale,, как и все классы в новом APIjava.time.

3.1. Шкала времени Java

Традиционный способ измерения времени - это деление дня на 24 часа по 60 минут по 60 секунд, что дает 86 400 секунд в день. Однако солнечные дни не всегда одинаково длинны.

Шкала времени UTC фактически позволяет дню иметь 86,399 или 86,401 секунд СИ. Секунда СИ является научной «Стандартной международной секундой» и определяется периодами излучения атома цезия 133). Это необходимо для того, чтобы день соответствовал Солнцу.

The Java Time-Scale divides each calendar day into exactly 86.400 subdivisions, known as seconds. Там нет високосных секунд.

3.2. Instant Класс

КлассInstant представляет момент на временной шкале. По сути, это числовая метка времени со стандартной эпохи Java1970-01-01T00:00:00Z.

Чтобы получить текущую метку времени, мы можем использовать статический методInstant.now(). Этот метод позволяет передать необязательный параметрClock. Если опущен, он использует системные часы в часовом поясе по умолчанию.

We can store start and finish times in two variables, as in previous examples. Затем мы можем вычислить время, прошедшее между обоими моментами.

Мы можем дополнительно использовать классDuration и его методbetween(), чтобы получить продолжительность между двумя объектамиInstant. Наконец, нам нужно преобразоватьDuration в миллисекунды:

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

4. StopWatchс

Переходя к библиотекам, Apache Commons Lang предоставляет классStopWatch, который можно использовать для измерения прошедшего времени.

4.1. Maven Dependency

Мы можем получить последнюю версию, обновив pom.xml:


    org.apache.commons
    commons-lang3
    3.7

Последнюю версию зависимости можно проверитьhere.

4.2. Измерение прошедшего времени сStopWatchс

Прежде всего, нам нужно получить экземпляр класса, а затем мы можем просто измерить прошедшее время:

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

Когда у нас запущены часы, мы можем выполнить код, который хотим протестировать, а затем, в конце, мы просто вызываем методstop(). Наконец, чтобы получить фактический результат, мы вызываемgetTime():

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. Это может быть полезно, если нам нужно сделать наш тест более сложным.

Наконец, отметим, что класс не является потокобезопасным.

5. Заключение

Есть много способов измерить время в Java. Мы рассмотрели очень «традиционный» (и неточный) способ, используяcurrentTimeMillis(). Кроме того, мы проверилиStopWatch Apache Common и рассмотрели новые классы, доступные в Java 8.

В целом, для простых и правильных измерений прошедшего времени достаточно методаnanoTime(). Он также короче, чемcurrentTimeMillis().

Отметим, однако, что для правильного тестирования производительности вместо ручного измерения времени мы можем использовать такую ​​платформу, как Java Microbenchmark Harness (JMH). Эта тема выходит за рамки данной статьи, но мы исследовалиit here.

Наконец, как всегда, код, использованный во время обсуждения, можно найтиover on GitHub.