1. 개요

이 기사에서는 Java에서 경과 시간을 측정하는 방법을 살펴 보겠습니다. 이것은 쉽게 들릴 수 있지만 우리가 알아야 할 몇 가지 함정이 있습니다.

경과 시간을 측정하는 기능을 제공하는 표준 Java 클래스 및 외부 패키지를 살펴 보겠습니다.

2. 간단한 측정

2.1. currentTimeMillis ()

Java에서 경과 시간을 측정해야하는 요구 사항이 발생하면 다음과 같이 시도 할 수 있습니다.

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

코드를 보면 완벽하게 이해할 수 있습니다. 시작시 타임 스탬프를 얻고 코드가 완료되면 다른 타임 스탬프를 얻습니다. 경과 시간은이 두 값의 차이입니다.

그러나 System.currentTimeMillis () 가 벽시계 시간을 측정 하므로 결과가 정확하지 않을 수 있습니다 . 벽시계 시간은 여러 가지 이유로 변경 될 수 있습니다. 예를 들어 시스템 시간을 변경하면 결과에 영향을 미치거나 윤초가 결과를 방해 할 수 있습니다.

2.2. 나노 타임 ()

java.lang.System  클래스의 또 다른 메소드 nanoTime () 입니다. Java 문서를 살펴보면 다음 문장을 찾을 수 있습니다.

"이 방법은 경과 시간 측정에만 사용할 수 있으며 시스템 또는 벽시계 시간의 다른 개념과 관련이 없습니다."

그것을 사용합시다 :

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

코드는 기본적으로 이전과 동일합니다. 유일한 차이점은 타임 스탬프를 얻는 데 사용되는 방법 입니다. currentTimeMillis () 대신 nanoTime () 입니다.

또한 nanoTime () 은 분명히 시간을 나노초 단위로 반환합니다. 따라서 경과 시간이 다른 시간 단위로 측정되면 그에 따라 변환해야합니다.

예를 들어 밀리 초로 변환하려면 결과를 나노초 단위로 1.000.000으로 나누어야합니다.

또 다른 함정 nanoTime는 () 이다 는 나노초 정밀도를 제공한다하더라도, 그것은 보증 나노초 해상도하지 않는 (즉, 값이 업데이트됩니다 얼마나 자주).

그러나 해상도가 적어도 currentTimeMillis () 만큼 우수하다는 것을 보장합니다  .

3. 자바 8

Java 8을 사용하는 경우 새로운 java.time.Instant  및 java.time.Duration 클래스를 사용해 볼 수 있습니다. 둘 다 변경 불가능하고 스레드로부터 안전하며 java.time API 내의 모든 클래스 마찬가지로 자체 시간 척도 인  Java Time-Scale을 사용합니다.

3.1. 자바 시간 척도

시간을 측정하는 전통적인 방법은 하루를 24 시간 60 분 60 초로 나누는 것으로 하루 86.400 초가됩니다. 그러나 태양 일이 항상 똑같이 긴 것은 아닙니다.

UTC 시간 척도는 실제로 하루에 86.399 또는 86.401 SI 초를 허용합니다. SI 초는 과학적 "표준 국제 초"이며 세슘 133 원자의 방사 기간으로 정의됩니다. 이것은 하루를 태양과 일치시키기 위해 필요합니다.

Java Time-Scale은 각 달력 일을 초로 알려진 정확히 86.400 개의 세분으로 나눕니다 . 윤초가 없습니다.

3.2. 인스턴트 클래스

인스턴트 클래스는 타임 라인에 즉시 나타냅니다. 기본적으로 1970-01-01T00 : 00 : 00Z 의 표준 Java epoch 이후의 숫자 타임 스탬프 입니다.

현재 타임 스탬프를 얻기 위해 Instant.now () 정적 메서드를 사용할 수 있습니다  . 이 메서드를 사용하면 선택적 Clock  매개 변수를 전달할 수 있습니다 . 생략하면 기본 시간대의 시스템 시계를 사용합니다.

이전 예제에서와 같이 시작 및 종료 시간을 두 개의 변수에 저장할 수 있습니다. 다음으로 두 순간 사이에 경과 된 시간을 계산할 수 있습니다.

Duration 클래스를  추가로 사용할 수  있으며 두 Instant 객체 사이의 기간을 얻기 위해 between () 메서드 입니다. 마지막으로 Duration 을 밀리 초로 변환해야합니다 .

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

4. 스톱워치

라이브러리로 이동하면 Apache Commons Lang은 경과 시간을 측정하는 데 사용할 수있는 StopWatch 클래스를 제공합니다  .

4.1. Maven 의존성

pom.xml을 업데이트하여 최신 버전을 얻을 수 있습니다.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.11</version>
</dependency>

최신 버전의 의존성은 여기에서 확인할 수 있습니다  .

4.2. 경과 시간 측정 스톱워치

우선, 우리는 클래스의 인스턴스를 얻어야합니다. 그리고 나서 우리는 단순히 경과 시간을 측정 할 수 있습니다 :

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

워치가 실행되면 벤치마킹하려는 코드를 실행할 수 있으며 마지막에 stop () 메서드 를 호출하기 만하면 됩니다. 마지막으로 실제 결과를 얻기 위해 getTime ()을 호출합니다 .

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

StopWatch  에는 측정을 일시 중지하거나 다시 시작하는 데 사용할 수있는 몇 가지 추가 도우미 메서드가 있습니다. 벤치 마크를 더 복잡하게 만들어야 할 경우 유용 할 수 있습니다.

마지막으로, 클래스는 스레드로부터 안전하지 않습니다.

5. 결론

Java에서 시간을 측정하는 방법에는 여러 가지가 있습니다. currentTimeMillis () 를 사용하여 매우 "전통적인"(그리고 부정확 한) 방법을 다루었습니다 . 또한 Apache Common의 StopWatch를 확인 하고 Java 8에서 사용할 수있는 새로운 클래스를 살펴 보았습니다.

전반적으로, 경과 된 시간을 간단하고 정확하게 측정하려면  nanoTime () 메서드로 충분합니다. 또한 currentTimeMillis () 보다 입력하는 것이 더 짧습니다 .

그러나 적절한 벤치마킹을 위해 시간을 수동으로 측정하는 대신 JMH (Java Microbenchmark Harness)와 같은 프레임 워크를 사용할 수 있습니다. 이 주제는이 기사의 범위를 벗어나지 만 여기서 살펴 보았습니다  .

마지막으로 항상 그렇듯이 토론 중에 사용 된 코드 는 GitHub 에서 찾을 수 있습니다  .