2 回答
TA贡献1851条经验 获得超5个赞
终于有时间更深入地研究这个问题了。
我开始实验,过了一段时间后发现,实际上并不是System.out.println它的存在影响了结果,而是你LocalDateTime在它之前实例化了2个实例。
深入挖掘LocalDateTime和SystemClock(它所委托的) 的代码,我发现亚毫级精度是通过调用本机调用 来实现的jdk.internal.misc.VM#getNanoTimeAdjustment。
最后一个调用是特定于操作系统的。我对它进行了一些实验,发现它不会线性返回值,因为它在循环中被调用(假设我的循环运行得相当规律)。
所以我决定运行一些代码来映射返回的纳米值。
我制作了这个示例代码:
Clock clock = Clock.systemDefaultZone();
int samples = 1_000;
LocalDateTime[] instants = new LocalDateTime[samples];
int k = 0;
for (int i = 0; i < samples; i++) {
instants[i] = LocalDateTime.now(clock);
for (int j = 0; j < 10000; j++) {
k = j % 2;
}
}
将值写入文件,然后将纳米差异与第一个值映射到图表中:
正如您所看到的,该图(包含 1000 个值)会出现间歇性跳跃。这显然部分是由于底层系统的精度限制造成的。但令我震惊的是,前两个值始终不同。就好像在定期访问时操作系统开始缓存该值一段时间(可能是为了避免系统资源紧张)。
但结果似乎是您设置自己在第三次和第四次调用时获得相同的值(除非已经过去了足够的时间)。
这可以解释为什么您的测试在没有这些先前实例的情况下通过,而失败。
顺便说一句,对于单元测试,您不想依赖系统时钟。确保您的业务代码从注入的 Clock 实例获取时间。然后,您可以注入自定义时钟进行测试,并测试您的代码是否会在 DST 转换日期或闰日运行,而无需等待几个月。
TA贡献1847条经验 获得超7个赞
该测试涉及竞争条件并通过(有时),因为时间和添加语句会改变时间并因此改变测试结果。
断言中检查的条件基本上是连续两个日期时间的纳秒部分是否相等。
鉴于默认情况下由System.currentTimeMillis()
内部使用并且它最多具有毫秒精度,如果获取纳秒数的第二个调用序列足够快(即导致在同一时间内完成调用的LocalDateTime.now
实际调用序列),则检查将成功。System.currentTimeMillis
毫秒作为第一个)。
当您在实际断言之前调用用于获取纳秒值的函数时,会加载相应的类,相应方法的代码会进入 CPU 缓存等。这使得第二对获取纳秒数的调用运行得更快。
添加回答
举报