StopWatch是java中的一个类库,翻译成中文是秒表的意思,顾名思义它的功能就是计时。

如上图,可见有很多个实现类库,api有些许差别,com.google.common.base.Stopwatch相比之下一些api更加灵活,因此项目中选用的是该Stopwtach。

二、为什么用StopWatch

计时功能常常在日志中用到,之前我们常用到的是: System.currentTimeMillis();

这里举例一个计算方法执行时间功能,代码如下:

    @Test
    public void test1() throws InterruptedException {
        long start = System.currentTimeMillis();
        Thread.sleep(1000);
        long end1 = System.currentTimeMillis();
        System.out.println((start - end1) / 1000);
        Thread.sleep(1000);
        long end2 = System.currentTimeMillis();
        System.out.println((start - end2) / 1000);

相比之下StopWatch更加优雅:

    @Test
    public void test2() throws InterruptedException {
        Stopwatch started = Stopwatch.createStarted();
        Thread.sleep(1000);
        System.out.println(started.elapsed(TimeUnit.SECONDS));
        Thread.sleep(1000);
        System.out.println(started.elapsed(TimeUnit.SECONDS));

就好像秒表按很多下计时键一样,统计出执行到每个步骤时消耗的时间。

三、怎么用

1.获取实例

获取Stopwatch有两种方式,分别是createUnstarted和createStarted

  • createUnstarted:只是获取一个Stopwatch实例
  • createStarted(常用) :获取一个Stopwatch实例,并立即开始计时
  • 2.elapsed(TimeUnit desiredUnit)

    返回Stopwatch经过的时间(可以指定返回的时间单位)

    3.isRunning

    判断计时器是否在运行状态

    4.start

    启动Stopwatch

    5.stop

    停止Stopwatch

    6.reset

    时间设置为0,状态设置为静止

    1.几个成员变量

    //时间源 
    private final Ticker ticker;
    //运行状态
    private boolean isRunning;
    //计时器stop前记录的时间
    private long elapsedNanos;
    //计时器开启时的时间
    private long startTick;
    

    2.Ticker类

    看上去没有什么可以灵活配置的地方

    public abstract class Ticker {
      protected Ticker() {}
      public abstract long read();
      @CheckReturnValue
      public static Ticker systemTicker() {
        return SYSTEM_TICKER;
      private static final Ticker SYSTEM_TICKER =
          new Ticker() {
            @Override
            public long read() {
              //实现就是System.nanoTime();
              return Platform.systemNanoTime();
    

    3.实例创建

    即调用工厂方法实例化一个Ticker赋值自己的实例变量ticker,started方法直接调用start方法。

      public static Stopwatch createStarted() {
        return new Stopwatch().start();
      public static Stopwatch createUnstarted() {
        return new Stopwatch();
      Stopwatch() {
        this.ticker = Ticker.systemTicker();
    

    4.start

      public Stopwatch start() {
        checkState(!isRunning, "This stopwatch is already running.");
        //计时器标记为启动
        isRunning = true;
        //获取当前系统时间作为startTick
        startTick = ticker.read();
        return this;
    

    5.stop

      public Stopwatch stop() {
        //获取当前系统时间
        long tick = ticker.read();
        checkState(isRunning, "This stopwatch is already stopped.");
        //计时器标记为停止
        isRunning = false;
        //记录一下暂停前记录的时间
        elapsedNanos += tick - startTick;
        return this;
    

    6.elapsed

      public long elapsed(TimeUnit desiredUnit) {
        //把时间转换为制定的单位
        return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
      //最后返回的就是当前计时的时间
      private long elapsedNanos() {
        //如果在运行,返回:(当前时间-最近一次开始时间)+最近一次开始前记录的时间
        //如果不在运行,返回记录的暂停前记录的时间
        return isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;
    

    7.reset

      public Stopwatch reset() {
        //暂停前记录的时间置为0
        elapsedNanos = 0;
        //运行状态置为停止
        isRunning = false;
        return this;
    

    五、参考资料

    GUAVA STOPWATCH源码解析