System.nanotime运行缓慢吗?

问题描述:

我的一个朋友向我展示了他所做的一些事情,并且我非常遗憾地解释了这可能发生的情况:他使用System.nanotime来计时,并且每隔一秒给用户一次更新以告知已经过了多少时间(Thread.sleep(1000)),并且它看起来是永远的(等待10秒钟需要大约3分钟才能完成)。我们尝试使用millitime来观察已经过了多少时间:它每秒都会显示已经经过了多少纳米量级,而且我们看到,每秒钟,纳米级每秒钟移动大约40-50毫秒。System.nanotime运行缓慢吗?

我检查了与System.nanotime和Java有关的错误,但它似乎是我能找到的唯一的东西,其中包括突然出现的节点greatly increasing and then stopping。我还浏览了this blog entry,这是基于我在另一个问题中读到的内容,但没有任何可能导致它的事情。

显然这可以通过使用millitime来解决这种情况;这里有很多解决方法,但是我很好奇的是,除了系统时钟或者至少是CPU最精确的时钟之外,还有其他问题(因为这就是System.nanotime似乎使用的)这可能导致它像这样一直运行缓慢?

long initialNano = System.nanoTime(); 
long initialMili = System.currentTimeMillis(); 
//Obviously the code isn't actually doing a while(true), 
//but it illustrates the point 
while(true) { 
    Thread.sleep(1000); 
    long currentNano = System.nanoTime(); 
    long currentMili = System.currentTimeMillis(); 
    double secondsNano = ((double) (currentNano - initialNano))/1000000000D; 
    double secondsMili = ((double) (currentMili - initialMili))/1000D; 
    System.out.println(secondsNano); 
    System.out.println(secondsMili); 
} 

secondsNano会沿着打印0.04线的东西,而secondsMili将打印的东西非常接近1

它看起来像沿着这条线已经报道Sun's bug database一个错误,但他们关闭它一个重复的,但他们的链接不会去现有的错误。它似乎是非常系统特定的,所以我越来越确信这是一个硬件问题。

+1

您可以提供有关您的环境的更多信息:操作系统,硬件,Java版本?我只是在我的机器上运行了你的样品,它产生了预期的结果(纳秒和毫秒每秒增加1,或多或少)。我的环境:Windows XP,Dell Optiplex,Sun JDK 1.6.0_14 – 2009-10-14 19:38:28

+0

不是我的机器,所以我会尽我所能:Windows XP SP3,Core Duo,JDK 1.6。我的猜测是,无论用什么java来计算nanoTime,这可能都是一个硬件问题,但我试图看看是否还有其他可能导致它的东西。 – DivineWolfwood 2009-10-14 20:50:49

+0

我试过你的代码(在Win XP,Core 2 Duo,Sun Java 1.6.0_16上),但是我不能重现这个问题。在我的系统中,纳秒/毫秒的时间在0.001秒内。 – Jesper 2009-10-15 08:26:18

......他用System.nanotime使程序做某件事之前要等待,...

你能告诉我们一些代码,演示正是他在做什么?是不是有些奇怪的那种繁忙的循环中,像这样:

long t = System.nanoTime() + 1000000000L; 
while (System.nanoTime() < t) { /* do nothing */ } 

如果是的话,那么这是不是让你的程序暂停了一段时间的正确方法。改用Thread.sleep(...)使程序等待指定的毫秒数。

+0

+1。不要忙 - 等。 – 2009-10-14 18:04:18

+0

这不是忙碌 - 等待:我将使用代码示例编辑问题,以更明确地了解究竟发生了什么。 – DivineWolfwood 2009-10-14 18:16:41

+0

想想更多,即使是在忙着等待,我们仍然会在这里看到相同的行为。我知道忙等待是不对的,但我想知道除了硬件故障之外是否还有其他可能导致上述一致性差异的问题。 – DivineWolfwood 2009-10-14 18:33:46

你知道你正在使用的循环并不需要精确的1秒来运行吗?首先Thread.sleep()不能保证是准确的,循环中的其余代码确实需要一些时间来执行(根据底层实现,nanoTime()和currentTimeMillis()实际上可能会很慢)。其次,System.currentTimeMillis()也不能保证准确(它只在某些操作系统和硬件组合上每隔50ms更新一次)。你也提到它不准确到40-50ms以上,然后继续说0.004s,实际上只有4ms。

我会建议你改变你的System.out.println()是:

System.out.println(secondsNano - secondsMili); 

这样一来,你就可以看到这两个时钟多少差异了第二逐秒基础。我在笔记本电脑上运行了大约12个小时,超过了1.46秒(快,不慢)。这表明这两个时钟有一些漂移。

我认为currentTimeMillis()方法可以在很长一段时间内提供更准确的时间,但是nanoTime()具有更高的分辨率,并且适用于计时代码或在短时间段内提供亚毫秒定时。

+0

我明白它并不需要一秒钟才能运行。然而,对于本质上相同的时间段,大约40-50ms的两个读数之一已经过去了,而另一个时钟读出大约1000ms已经过去了。这是一致的,我不能在任何其他系统上重现它。在这一点上,我基本上已经准备好将它归档到一些奇怪的操作系统/ BIOS /硬件问题,因为我不认为我可以找到任何其他原因来解释这一点。 – DivineWolfwood 2009-11-21 00:14:16

+0

我也在原始文章中更正了.004:我的意思是说已经注册了0.04秒。感谢您的支持。 – DivineWolfwood 2009-11-21 00:16:25

我遇到过同样的问题。除了我的情况,它更明显。

有了这个简单的程序:

public class test { 
    public static void main(String[] args) { 
     while (true) { 
      try { 
       Thread.sleep(1000); 
      } 
      catch (InterruptedException e) { 
      } 

      OStream.out("\t" + System.currentTimeMillis() + "\t" + nanoTimeMillis()); 
     } 
    } 

    static long nanoTimeMillis() { 
     return Math.round(System.nanoTime()/1000000.0); 
    } 
} 

我得到如下结果:

13:05:16:380 main: 1288199116375 61530042 
13:05:16:764 main: 1288199117375 61530438 
13:05:17:134 main: 1288199118375 61530808 
13:05:17:510 main: 1288199119375 61531183 
13:05:17:886 main: 1288199120375 61531559 

的nanoTime是只显示400毫秒〜经过每个第二。