본문 바로가기

Programing/Framework

[SpringFramework] StopWatch (Spring vs Apache)

자바에서 두 점 사이의 시간을 재는 방법에는 currentTimeMillis 와 nanoTime가 있다.

이 정적메서드에 대해서는 지난 주에 심층(?) 분석을 해보았다. [JVM] currentTimeMillis vs nanoTime

 

하지만 직접 날 것(raw)의 메서드로 사용할 대는 응집성이 떨어질 수 있으므로 스톱와치와 같은 실세상과 비슷한 유틸리티 클래스를 이용하면 좋을 것이다.

 

이 글은 스프링의 StopWatch에 대해 적으려고 하였지만 사실 Apache Commons Lang 유틸리티에도 StopWatch를 가지고 있었다.

스프링의 StopWatch

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/StopWatch.html

 

내부 코드를 살짝 보았는데, 구현은 currentTimeMillis을 통해 하고 있다.

참고로 spring-core에 코드가 있다. 2001년 5월에 추가되었고 스프링의 창시자 로드존슨(Rod Johnson)을 비롯한 Juergen Hoeller, Sam Brannen 가 저자로 적혀있다.

 

StopWatch 클래스에는 내부 클래스 TaskInfo이 있다.

public static final class TaskInfo {

   private final String taskName;

   private final long timeMillis;

연결리스트로 관리되고 stop을 할 때마다 추가가 된다. (아래 코드는 가독성을 위해 많은 코드가 지워졌다.)

public class StopWatch {

private final List<TaskInfo> taskList = new LinkedList<>();

public void stop() throws IllegalStateException {
   if (this.currentTaskName == null) {
      throw new IllegalStateException("Can't stop StopWatch: it's not running");
   }
   long lastTime = System.currentTimeMillis() - this.startTimeMillis;
   this.totalTimeMillis += lastTime;
   this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
   if (this.keepTaskList) {
      this.taskList.add(this.lastTaskInfo);
   }
   ++this.taskCount;
   this.currentTaskName = null;
}

아파치의 StopWatch

https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/time/StopWatch.html

반면에 Apache  Commons Langs의 time 패키지 하위의 StopWatch는 시간 계산을 동시에 두가지 방법을 모두 사용한다.

public class StopWatch {

  /**
    * The start time.
    */
   private long startTime;

  /**
    * The start time in Millis - nanoTime is only for elapsed time so we
    * need to also store the currentTimeMillis to maintain the old
    * getStartTime API.
    */
   private long startTimeMillis;

    public void start() {
      if (this.runningState == State.STOPPED) {
      throw new IllegalStateException("Stopwatch must be reset before being restarted. ");
    }
    if (this.runningState != State.UNSTARTED) {
     throw new IllegalStateException("Stopwatch already started. ");
    }
    this.startTime = System.nanoTime();
    this.startTimeMillis = System.currentTimeMillis();
    this.runningState = State.RUNNING;
  }

하지만 stop 메서드를 보면 namoTime()만 스냅샷을 찍는 걸로 보아서 결국 nanoTime()을 시간 계산으로 쓴다는 것을 알 수 있다.

사실은 위에 인스턴스 변수 선언의 주석에도 쓰여있다.

public void stop() {
    if (this.runningState != State.RUNNING && this.runningState != State.SUSPENDED) {
        throw new IllegalStateException("Stopwatch is not running. ");
    }
    if (this.runningState == State.RUNNING) {
        this.stopTime = System.nanoTime();
    }
    this.runningState = State.STOPPED;
}

 

Apache는 nanoTime()을 쓰고 Spring은 currentTimeMillis()을 쓴다.

역시 Ummm님이 스프링의 유틸리티를 싫어하는 데에는 이유가 있었다.

 

2019년 8월 7일 스프링의 StopWatch 클래스도 단조 증가 시계로 바뀌었다.

https://github.com/spring-projects/spring-framework/issues/23235 참고~

---

2021-09-01 새 에디터에 맞춰 코드 수정 및 업데이트

더보기

 

구 소스코드
중간과정: 일부는 틀안에 틀이 하나 더 있다.
현재: 2021-09-01