Guava 中的 Stopwatch 是个什么鬼?

公众号程序猿DD

共 3406字,需浏览 7分钟

 ·

2020-10-16 15:00

点击上方蓝色“程序猿DD”,选择“设为星标”

回复“资源”获取独家整理的学习资料!

Stopwatch 解释为计时器,又称秒表、停表,很明显它是记录时间的。


# 如何使用


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

安卓使用:

Stopwatch.createStarted(         new Ticker() {           public long read() {             return android.os.SystemClock.elapsedRealtime();            }          });}

看了上面这段代码,有人会说,不用Stopwatch 照样可以实现执行时间的统计,比如:

   long startTime = System.currentTimeMillis();
try { // 模拟业务逻辑 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(System.currentTimeMillis() - startTime);

确实是,这样也能统计这段代码的执行时间,那么为什么还会有Stopwatch(我也有这种想法)


官方称不直接使用System#nanoTime是有一下几个原因:


  • 时间源可以替代 可以重写Ticker(下面会介绍)

  • nanoTime的返回值是纳秒,返回的值没有意义,Stopwatch抽象返回值


下面从实现方式来分析下guava为什么会设计这么类


# 源码分析


内部有几个成员变量

  //时间源 一般和Stopwatch一起使用,而不是单独使用  private final Ticker ticker;  private boolean isRunning;  private long elapsedNanos;  private long startTick;

先看下Ticker(是个abstract类) 都有什么:

  public static Ticker systemTicker() {    return SYSTEM_TICKER;  }
private static final Ticker SYSTEM_TICKER = new Ticker() { @Override public long read() { // 实际上就是System.nanoTime(); return Platform.systemNanoTime(); } }; // 子类重写    public abstract long read();

回到Stopwatch,看下它的构造方式:


  public static Stopwatch createUnstarted() {    return new Stopwatch();  }
/** * Creates (but does not start) a new stopwatch, using the specified time source. * * @since 15.0 */ public static Stopwatch createUnstarted(Ticker ticker) { return new Stopwatch(ticker); }
/** * Creates (and starts) a new stopwatch using {@link System#nanoTime} as its time source. * * @since 15.0 */ public static Stopwatch createStarted() { return new Stopwatch().start(); } Stopwatch() { this.ticker = Ticker.systemTicker(); }
Stopwatch(Ticker ticker) { this.ticker = checkNotNull(ticker, "ticker"); }
  

包括创建不启动,创建启动的构造方式


执行流程


start--> stop 或者 reset


看下代码,很简单

 public Stopwatch start() {    // 先判断是否处于执行状态    checkState(!isRunning, "This stopwatch is already running.");    isRunning = true;    // 初始化 当前的纳秒时间    startTick = ticker.read();    return this;  }
public Stopwatch stop() { long tick = ticker.read(); checkState(isRunning, "This stopwatch is already stopped."); isRunning = false; elapsedNanos += tick - startTick; return this; } public Stopwatch reset() { elapsedNanos = 0; isRunning = false; return this;  }

获取结果的代码:

  // 计算纳秒  private long elapsedNanos() {    return isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;  }
// 转换其他单位 public long elapsed(TimeUnit desiredUnit) { return desiredUnit.convert(elapsedNanos(), NANOSECONDS); }
还有一些单位转换和toString方法,就不分析了


# 总结


  • 支持TimeUnit,可以将计算后的时间转换为各种单位 比如:stopwatch.elapsed(TimeUnit.SECONDS))

  • 同一个Stopwatch,可以重置,重复记录

  • 时间源可以替代 可以重写Ticker

  • 其他 Spring 也有StopWatch 实现方式差不多,不支持替换时间源和可以重置,支持毫秒和纳秒,但是增加了Task的概念

来源:https://my.oschina.net/lowkeysoft/blog/1595755


往期推荐

为什么 Redis 单线程能支撑高并发?

华为又一战略级生态启程:华为IdeaHub 使能千行百业

必须了解的 MySQL 三大日志

说了低调...这下百度知道了...

离职半年了,最近又开始被吐槽输出不够...


扫一扫,关注我

一起学习,一起进步

每周赠书,福利不断

深度内容

推荐加入


最近热门内容回顾   #技术人系列

浏览 15
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报