我的一位朋友向我展示了他所做的一些事情,我非常想解释这是怎么发生的:他正在使用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已经报告了此行中的错误,但是他们将其作为重复项关闭,但是他们的链接不会转到现有错误。它似乎是特定于系统的,因此我越来越确定这是一个硬件问题。
答案 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毫秒。