GUAVA STOPWATCH源码解析

问题

一直在使用如下代码进行程序耗时计算和性能调试,但是对其返回值代表的具体意义却不甚了解。

Stopwatch stopwatch = Stopwatch.createStarted();
doSomething();
stopwatch.stop(); // optional
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch); // formatted string like "12.3 ms"

查看源码发现其代码并不复杂,下面就对其源码进行剖析和解释。

源码剖析

public final class Stopwatch {
  private final Ticker ticker;//计时器,用于获取当前时间
  private boolean isRunning;//计时器是否运行中的状态标记
  private long elapsedNanos;//用于标记从计时器开启到调用统计的方法时过去的时间
  private long startTick;//计时器开启的时刻时间
}

通过对elapsedNanos、startTick结合当前时刻时间,可以计算出我们所需要的程序运行流逝的时间长度。

首先来看Ticker工具类:

public static Stopwatch createStarted() {
    return new Stopwatch().start();
}

Stopwatch() {
    this.ticker = Ticker.systemTicker();
  }


private static final Ticker SYSTEM_TICKER =
      new Ticker() {
        @Override
        public long read() {
          //ticker工具类read方法,直接获取机器的毫秒时间
          return Platform.systemNanoTime();
        }
      };


static long systemNanoTime() {
    return System.nanoTime();
  }

StopWatch的几个关键方法:

public Stopwatch start() {
    checkState(!isRunning, "This stopwatch is already running.");
    isRunning = true;
    startTick = ticker.read();//设置startTick时间为stopwatch开始启动的时刻时间
    return this;
  }
public Stopwatch stop() {
    long tick = ticker.read();
    checkState(isRunning, "This stopwatch is already stopped.");
    isRunning = false;
    //设置elapsedNanos时间为方法调用时间-stopwatch开启时间+上次程序stopwatch的elapsedNanos历史时间 
    elapsedNanos += tick - startTick;
    return this;
  }

public long elapsed(TimeUnit desiredUnit) {
    return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
  }


private long elapsedNanos() {
    //如果stopwatch仍在运行中,返回当前时刻时间-stopwatch开启时刻时间+历史elapsedNanos时间(elapsedNanos只在stop和reset时会更新)
    //如果stopwatch已停止运行,则直接返回elapsedNanos,详见stop()
    return isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;
  }

结论

调用方式1:

Stopwatch stopwatch = Stopwatch.createStarted();
doSomething();
stopwatch.stop(); // optional
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch); // formatted string like "12.3 ms"

使用stopwatch对程序运行时间进行调试,首先调用StopWatch.createStarted()创建并启动一个stopwatch实例,调用stopwatch.stop()停止计时,此时会更新stopwatch的elapsedNanos时间,为stopwatch开始启动到结束计时的时间,再次调用stopwatch.elapsed(),获取stopwatch在start-stop时间段,时间流逝的长度。

调用方式2:

Stopwatch stopwatch = Stopwatch.createStarted();
doSomething();
//stopwatch.stop();
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch); // formatted string like "12.3 ms"

createStarted启动了一个stopwatch实例,stopwatch的时间持续流逝,调用elapsed方法,返回isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;,此时得到的返回值是当前时间和stopwatch.start()时刻时间的时间差值,所以是一个持续递增的时间。

如果需要在程序中对关键步骤的每一步进行进行持续度量,需要使用如下调用方式

Stopwatch stopwatch = Stopwatch.createStarted();
doSomething();
stopwatch.stop();
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch); // formatted string like "12.3 ms"

stopwatch.reset().start();
doSomething();
stopwatch.stop();
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch); // formatted string like "12.3 ms"

你可能感兴趣的:(GUAVA STOPWATCH源码解析)