一尘不染

Java System.nanoTime()完全没用吗?

java

如在x86系统上的博客文章“ 当心 Java中的System.nanoTime()”中所述,Java的System.nanoTime()使用CPU专用计数器返回时间值。现在考虑以下情况,我用它来衡量通话时间:

long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;

现在,在多核系统中,可能是在测量了time1之后,将该线程调度到了另一个计数器,该计数器的计数器小于以前的CPU的计数器。因此,我们可以在time2中获得一个小于 time1的值。因此,我们将在timeSpent中得到一个负值。

考虑到这种情况,System.nanotime暂时还没有用吗?

我知道更改系统时间不会影响纳米时间。那不是我上面描述的问题。问题在于,每个CPU自打开以来都会保留一个不同的计数器。与第一个CPU相比,该计数器在第二个CPU上可以更低。由于操作系统可以在获取time1之后将线程调度到第二个CPU,因此timeSpent的值可能不正确,甚至为负数。


阅读 1529

收藏
2020-03-05

共2个答案

一尘不染

从当时的Sun JDK在当时的操作系统上运行的观点来看,该答案写于2011年。那是很久以前的事!列文托夫的答案提供了最新的观点。

该帖子是错误的,并且nanoTime很安全。Sun的实时与并发专家David Holmes对该博文进行了评论,并链接到该博文。它说:

使用QueryPerformanceCounter / QueryPerformanceFrequency API实现System.nanoTime()。QPC使用的默认机制由硬件抽象层(HAL)确定。版本。例如,由于TSC无法在SMP系统中的不同处理器上同步的问题,Windows XP Service Pack 2更改了使用电源管理计时器(PMTimer)而不是处理器时间戳计数器(TSC)的功能。会根据电源管理设置而变化(并因此而变化与经过时间的关系)。

因此,在Windows上,直到WinXP SP2之前,这都是一个问题,但现在不是。

我找不到涉及其他平台的第二部分(或更多部分),但是该文章的确包含了Linux已经以相同的方式遇到并解决了相同问题的注释,并带有指向clock_gettime(CLOCK_REALTIME)的常见问题的链接。,其中说:

在所有处理器/内核中,clock_gettime(CLOCK_REALTIME)是否一致?(是否重要?例如ppc,arm,x86,amd64,sparc)。
它应该或被认为是越野车。

但是,在x86 / x86_64上,可能会看到未同步或可变的频率TSC导致时间不一致。2.4内核确实没有针对此的保护措施,而早期的2.6内核在这里也不是很好。从2.6.18版开始,用于检测此错误的逻辑会更好,我们通常会退回到安全的时钟源。

ppc始终具有同步的时基,因此这不成问题。

因此,如果Holmes的链接可以被理解为暗示着nanoTime调用clock_gettime(CLOCK_REALTIME),那么从x86上的内核2.6.18开始,并且始终在PowerPC上,它是安全的(因为IBM和Motorola与Intel不同,实际上知道如何设计微处理器)。

遗憾的是,没有提到SPARC或Solaris。当然,我们不知道IBM JVM做什么。但是现代Windows和Linux上的Sun JVM可以实现这一目标。

编辑:这个答案是基于它引用的来源。但是我仍然担心这实际上可能是完全错误的。一些最新的信息将非常有价值。我刚找到一个指向Linux时钟的四年更新文章的链接,该文章可能会有用。

2020-03-05
一尘不染

使用Spring EL:

@Value("#{'${my.list.of.strings}'.split(',')}") 
private List<String> myList;

假设使用以下内容正确加载了属性文件:

my.list.of.strings=ABC,CDE,EFG
2020-03-05