问题来源
以下是 zookeeper3.4.12 源码里的一小部分:

注释里有一句话是在读不懂:
Time.currentElapsedTime will change but nanoTime won't.
个人感觉应该是写错了(根据返回值,明显要变两个一起变),这里应该是说的 currentTimeMillis() 和 nanoTime() 的区别。
于是去 jdk 1.8 官方文档看了一下它们的区别(native 方法,看不见代码):
nanoTime()
以纳秒为单位返回正在运行的Java虚拟机的高分辨率时间源的当前值。
该方法只能用于测量经过时间,与系统或挂钟时间的任何其他概念无关。 返回的值表示纳秒,因为一些固定但任意的起始时间(可能在将来,所以值可能是负数)。 在Java虚拟机的实例中,该方法的所有调用都使用相同的来源; 其他虚拟机实例可能会使用不同的来源。
该方法提供纳秒精度(precision),但不一定是纳秒分辨率(resolution 即,值的变化频率) - 除了分辨率至少与currentTimeMillis() 的分辨率不同之外,不作任何保证 。
跨越大约292年( 纳秒)的连续呼叫的差异将无法正确计算由于数字溢出所造成的时间。
仅当在Java虚拟机的同一实例中获得的两个此类值之间的差异被计算时,此方法返回的值才会变得有意义。
例如,测量代码执行多长时间:
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
比较两个nanoTime值
long t0 = System.nanoTime(); ... long t1 = System.nanoTime();
应该使用t1 - t0 < 0 ,而不是t1 < t0 ,因为数值溢出的可能性。
返回:运行Java虚拟机的高分辨率时间源的当前值,以纳秒为单位
从以下版本开始:
1.5
currentTimeMillis()
返回当前时间(以毫秒为单位)。 请注意,虽然返回值的时间单位为毫秒,但该值的粒度(granularity)取决于底层操作系统,并且可能较大。 例如,许多操作系统以几十毫秒为单位测量时间。
有关“计算机时间”和协调世界时间(UTC)之间可能出现的轻微差异的讨论,请参阅类 Date 的说明。
返回:当前时间和1970年1月1日UTC之间的零点之间的差值,以毫秒为单位。
总结
区别:
1. 用途:
nanoTime() 不会单个出现,它用来精确地求时间差;
currentTimeMillis() 往往和 Date() 有关,例如 Date() 的源码:
public Date() {
this(System.currentTimeMillis());
}
2. 精度:
nanoTime() 纳秒;
currentTimeMillis() 取决于底层操作系统,有可能是几十毫秒
3. 相关性:
nanoTime() 与虚拟机的实例有关,不同虚拟机的实例之间比较无意义;
currentTimeMillis() 与系统设置的 UTC 时间有关,例如 win10 的 UTC 设置:

原问题分析
zookeeper 源码中的注释应该错了,应该是:
The difference is that if somebody changes the system clock,
currentTimeMillis will change but nanoTime won't.
感想和吐槽
看源码真的能暴露问题啊!
暴露源码的问题?

本文详细解析了Java中nanoTime()与currentTimeMillis()两种时间获取方法的区别,包括它们的用途、精度和相关性。并通过Zookeeper源码中的一处注释引发的思考,深入探讨了这两种方法在实际应用中的考量。
860

被折叠的 条评论
为什么被折叠?



