System.nanotime运行缓慢?

时间:2009-10-14 17:57:47

标签: java nanotime

我的一位朋友向我展示了他所做的一些事情,我非常想解释这是怎么发生的:他正在使用System.nanotime来计时,并且它每秒都给用户一个更新告诉已经过了多少时间(该部分的Thread.sleep(1000)),它看似永远(等待10秒钟的事情需要大约3分钟才能完成)。我们尝试使用millitime来查看已经过了多长时间:它打印了每秒经过多少纳米时间,我们看到每秒钟纳米时间每秒移动大约40-50毫秒。

我检查了与System.nanotime和Java有关的错误,但似乎我发现的唯一一件事突然涉及纳米时代greatly increasing and then stopping。我也根据我在另一个问题中阅读的内容浏览了this blog entry,但是没有任何可能导致它的内容。

显然,只需使用毫秒,就可以解决这种情况;有很多解决方法,但我很好奇的是,除了系统时钟的硬件问题或者至少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已经报告了此行中的错误,但是他们将其作为重复项关闭,但是他们的链接不会转到现有错误。它似乎是特定于系统的,因此我越来越确定这是一个硬件问题。

3 个答案:

答案 0 :(得分:4)

  

...他正在使用System.nanotime使程序在做某事之前等待,并且......

你能告诉我们一些能够准确证明他在做什么的代码吗?这是一种奇怪的繁忙循环,像这样:

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

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

答案 1 :(得分:3)

您是否意识到您正在使用的循环不需要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()具有更高的分辨率,适用于时序码或在短时间内提供亚毫秒时序。

答案 2 :(得分:1)

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

通过这个简单的程序:

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毫秒。