2

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

我检查了与 System.nanotime 和 Java 相关的错误,但似乎我能找到的唯一事情涉及 nanotime 突然大幅增加然后停止。我还根据我在另一个问题中阅读的内容浏览了此博客条目,但没有任何可能导致它的内容。

显然,这可以通过只使用毫秒来解决这种情况;有很多解决方法,但我很好奇的是,除了系统时钟的硬件问题或至少 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 的错误数据库中已经报告了沿着这条线的错误,但他们将其作为副本关闭,但他们的链接没有指向现有错误。它似乎是特定于系统的,所以我越来越确定这是一个硬件问题。

4

3 回答 3

4

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

你能给我们看一些代码来准确地展示他在做什么吗?是不是某种奇怪的繁忙循环,像这样:

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

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

于 2009-10-14T18:02:43.407 回答
3

您确实意识到您正在使用的循环运行并不需要 1 秒?首先 Thread.sleep() 不能保证是准确的,并且循环中的其余代码确实需要一些时间来执行(nanoTime() 和 currentTimeMillis() 实际上都可能非常慢,具体取决于底层实现)。其次, System.currentTimeMillis() 也不能保证准确(在某些操作系统和硬件组合上,它仅每 50 毫秒更新一次)。您还提到它不准确到上面的 40-50 毫秒,然后继续说 0.004 秒,实际上只有 4 毫秒。

我建议您将 System.out.println() 更改为:

System.out.println(secondsNano - secondsMili);

这样,您将能够逐秒查看两个时钟的差异。我让它在我的笔记本电脑上运行了大约 12 个小时,它在 1.46 秒后就结束了(快,而不是慢)。这表明两个时钟存在一些漂移。

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

于 2009-11-20T23:33:26.930 回答
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 毫秒。

于 2010-10-27T17:15:19.750 回答