likes
comments
collection
share

还在用传统的System.currentTimeMillis来计算代码运行时间嘛?

作者站长头像
站长
· 阅读数 23

还在用传统的System.currentTimeMillis来计算代码运行时间嘛?

计算耗时的方法

常见的计算一段代码的耗时情况都是计算开始时间点的时间戳,然后在结束的时候用当前时间戳减去之前记录好的,例如:

Long starTime = System.currentTimeMillis();

// ....

Long runTime = System.currentTimeMillis() - starTime;

但如果我说这个方式其实是错的,不准确的,是不是有点颠覆你的认知。

还在用传统的System.currentTimeMillis来计算代码运行时间嘛?

先把结论放这里:

System.currentTimeMillis用的是墙上时钟,墙上时钟在计算时间间隔有可能会有误差,计算时间间隔应该用单调时钟System.nanoTime

短时间方法内测一下倒是也没关系,如果是长作业任务测量执行时间,最好还是用单调时钟。

依赖时钟的方式

首先将一下日常开发中,我们 应用程序会以各种方式依赖时钟,大致类别有:时间间隔时间点

时间间隔

  • 某个请求是否超时
  • 某项服务99%的响应时间是多少
  • QPS、TPS

时间点

  • 文章定时发送、定时推送消息
  • 缓存条目何时过期

时钟种类

  • 单调时钟
  • 墙上时钟(钟表时间)

墙上时钟

根据某个日历(参照时间)返回当前的日期与时间。

Java中的System.currenTimeMillis就是典型的墙上时钟。

他会返回自1970年1月1日以来的秒数和毫秒数(不含闰秒)。

时钟回拨:

如果本地时钟远远快于NTP服务器,强制重制后会跳回到先前的某个时间点

这种跳跃是忽略闰秒的。所以墙上时钟不适合用来测量时间间隔

闰秒:由于地球的不均匀自转长期变慢性。会使世界时原子时之间相差正负0.9秒。

但出现这种情况时,就要把世界时往前或者往后拨动1秒。

就有可能会出现那一分钟少了一秒或者多了一秒:9:46:59秒 9:46:60秒

单调时钟

单调时钟更适合测量时间段(时间间隔),例如超时或者服务的响应时间

Java中的System.nanoTime。返回的就是单调时钟。

单调时钟,意味着他永远都是向前,不会出现墙上时钟回拨的现象。

在开发中,我们肯定会写过在某个动作开始前用System.currenTimeMillis获取时间戳,然后在结束的时间再获取一次,然后两者相见。

但其实这种最好是用单调时间来做,因为墙上时钟会有时钟回拨的问题,不适测量时间点。

单调时钟参考的可能是电脑启动以后经历的纳秒数或者是其他。因此比较不同节点上的单调时钟差值毫无意义

时钟摆动:

如果本地的单调时钟快于或慢于NTPNTP会控制本地石英的振动频率(也叫摆动)。

总结

  • 时钟分为墙上时钟单调时钟
  • 墙上时钟Sytem.currenTimeMillis单调时钟System.nanoTime
  • 墙上时钟出现时钟时钟回拨时会忽略闰秒,所以不适合用于测量时间间隔。

下一篇讲讲分布式系统中的2个最不可靠的组件不可靠时钟,图灵机得主Lamport老爷子有一篇关于时钟的的论文 《Time, Clocks, and the Ordering of Events in a Distributed System》,这篇论文也是在分布式领域被引用最多的。

转载自:https://juejin.cn/post/7240374267697791034
评论
请登录