Java System.nanoTime()是否完全无用?

Java System.nanoTime()是否完全无用?,java,nanotime,Java,Nanotime,正如博客文章中所述,在x86系统上,Java的System.nanoTime()使用特定计数器返回时间值。现在考虑下面的例子,我用它来测量呼叫时间: long time1= System.nanoTime(); foo(); long time2 = System.nanoTime(); long timeSpent = time2-time1; 现在在一个多核系统中,可能是在测量了time1之后,线程被调度到一个不同的处理器上,该处理器的计数器小于前一个CPU的计数器。因此,我们可以在tim

正如博客文章中所述,在x86系统上,Java的System.nanoTime()使用特定计数器返回时间值。现在考虑下面的例子,我用它来测量呼叫时间:

long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;
现在在一个多核系统中,可能是在测量了time1之后,线程被调度到一个不同的处理器上,该处理器的计数器小于前一个CPU的计数器。因此,我们可以在time2中得到一个小于time1的值。因此,我们将得到一个负的时间消耗值

考虑到这种情况,是不是System.nanotime现在几乎毫无用处


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

不,它不是。。。这取决于你的CPU,检查如何/为什么根据CPU不同对待事物

基本上,阅读Java的源代码,检查您的版本对函数的作用,以及它是否对CPU起作用,您将在其上运行它


您可以将其用于性能基准测试(2008年发布,但已更新)。

Java 5文档也建议出于同样的目的使用此方法

此方法只能用于 测量经过的时间,而不是 与系统的任何其他概念相关 或者挂钟时间


对于运行Windows XP和JRE 1.5.0的Core 2 Duo,这似乎不是问题

在一个有三个线程的测试中,我看不到System.nanoTime()正在倒退。处理器都很忙,线程偶尔会进入睡眠状态以引起线程的移动


[编辑]我猜这只会发生在物理上独立的处理器上,也就是说,计数器对同一个芯片上的多个核心进行同步。

我做了一些搜索,发现如果一个是迂腐的,那么它可能被认为是无用的……在特定情况下……这取决于您的需求对时间的敏感程度

从Java Sun站点签出:

实时时钟和 System.nanoTime()都基于 相同的系统调用,因此相同 时钟

使用JavaRTS,所有基于时间的API (例如,计时器、定期 线程、截止日期监视等等 第四)基于 高分辨率定时器。而且,一起 通过实时优先级,他们可以 确保将使用适当的代码 在适当的时间执行 实时约束。相反, 普通的JavaSEAPI只提供了一些 能够处理的方法 高分辨率时间,无需 在指定时间执行的保证 时间在之间使用System.nanoTime() 代码中要执行的各个点 运行时间测量应 永远要准确

Java还有一个方法:

此方法只能用于 测量经过的时间,而不是 与系统的任何其他概念相关 或者挂钟时间。返回的值 表示自某些 固定但任意的时间(可能在 因此,价值观可能是 否定)。此方法提供 纳秒精度,但不是 必须是纳秒精度。不 保证如何进行 值经常变化。分歧 在跨度更大的连续调用中 大约292.3年(263 纳秒)将不准确 计算由于数值原因而经过的时间 溢出

似乎可以得出的唯一结论是,nanoTime()不能作为一个准确的值。因此,如果不需要测量相隔仅纳秒的时间,那么即使结果返回值为负值,该方法也足够好。然而,如果您需要更高的精度,他们似乎建议您使用JavaRTS


因此,为了回答您的问题…no nanoTime()并非毫无用处…这并不是在任何情况下都要使用的最谨慎的方法。

Linux会纠正CPU之间的差异,但Windows不会。我建议您假设System.nanoTime()仅精确到1微秒左右。获得更长时间的一个简单方法是调用foo()1000次或更多次,然后将时间除以1000。

绝对不是无用的。计时爱好者正确地指出了多核问题,但在实际的word应用程序中,它通常比currentTimeMillis()要好得多

在计算帧刷新中的图形位置时,nanoTime()会使程序中的运动更加平滑

我只在多核机器上进行测试。

我看到使用System.nanoTime()报告的运行时间为负。明确地说,有关守则是:

    long startNanos = System.nanoTime();

    Object returnValue = joinPoint.proceed();

    long elapsedNanos = System.nanoTime() - startNanos;
变量“elapsednos”的值为负值。(我肯定中间调用也用了不到293年的时间,这是存储在longs中的nano的溢出点:)

这是在运行AIX的IBM P690(多核)硬件上使用IBM v1.5 JRE 64位实现的。我只见过这种错误发生一次,所以它似乎非常罕见。我不知道原因-是硬件特定的问题,JVM缺陷-我不知道。一般来说,我也不知道nanoTime()的准确性会受到什么影响


为了回答最初的问题,我不认为纳米时间是无用的——它提供了亚毫秒的计时,但有一个实际的(不仅仅是理论上的)您需要考虑的是不准确的风险。

这个答案是在2011年从当时运行在操作系统上的Sun JDK的实际操作角度得出的。那是很久以前的事了!提供更具时代感的视角。

那篇文章是错误的,
nanoTime
是安全的。这篇帖子上有一条评论,链接到Sun的一位实时并发人员
jlong os::javaTimeMillis() {
  timeval time;
  int status = gettimeofday(&time, NULL);
  assert(status != -1, "linux error");
  return jlong(time.tv_sec) * 1000  +  jlong(time.tv_usec / 1000);
}


jlong os::javaTimeNanos() {
  if (Linux::supports_monotonic_clock()) {
    struct timespec tp;
    int status = Linux::clock_gettime(CLOCK_MONOTONIC, &tp);
    assert(status == 0, "gettime error");
    jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
    return result;
  } else {
    timeval time;
    int status = gettimeofday(&time, NULL);
    assert(status != -1, "linux error");
    jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec);
    return 1000 * usecs;
  }
}