⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7240374267697791034 「Ashleejy」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

Java中的时钟

计算耗时的方法

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

Long starTime = System.currentTimeMillis();

// ....

Long runTime = System.currentTimeMillis() - starTime;

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

颠覆你的认知

先把结论放这里:

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」
  • 墙上时钟出现时钟**「时钟回拨」**时会忽略闰秒,所以不适合用于测量时间间隔。

分布式系统中一定要注意不可靠时钟

文章目录
  1. 1. 计算耗时的方法
  2. 2. 依赖时钟的方式
  3. 3. 时钟种类
  4. 4. 墙上时钟
  5. 5. 单调时钟
  6. 6. 总结