今天在看以前代码时,突然想起一个问题:在windows xp上,使用System.currentTimeMillis来得到当前时间毫秒值,但是它的精度只有15ms到16ms,而不是1ms。
这个问题相当严重,因为我们平时经常会在代码中这样来计算代码的运行时间:
long start = System.currentTimeMillis();
// ... some code
long end = System.currentTimeMillis();
System.out.println("Your code cost: " + (end-start) + "ms");
可惜的是,如果你要测量的代码运行得比较快的话,就会发现,其值要么是0ms,要么是15ms。没有0-15ms之间的值。
我想到以前做过的一个项目,在日志中检查每一条信息接收时的毫秒值和发送时的毫秒值,以记录延时。但是统计时发现,要么就是0ms,要么就是15ms以上,中间这一块数据都去哪儿了?
所以如果要求很精确的话,这种方式是不可靠的(在windows上)。
在群友们的帮助下,在不同的操作系统中运行以下代码:
public class MillisTime {
public static void main(String[] args) {
long start = 0;
long end = 0;
while (true) {
if (start == 0) {
start = System.currentTimeMillis();
} else {
long current = System.currentTimeMillis();
if (current != start) {
end = current;
break;
}
}
}
System.out.println("The time interval of your OS: " + (end - start) + "ms");
}
}
得到的结果如下:
看来只有windows xp最菜。
毫秒不行,那纳秒呢?我们知道还有一个System.nanoTime()方法呢。(注:1ms = 1,000,000ns )
我猜想,在windows xp中,既然时间精度只有15ms,那么使用nanoTime应该也得到同样的值,即15000000ns。于是运行以下代码:
public class NanoTime {
public static void main(String[] args) {
long start = 0;
long end = 0;
while (true) {
if (start == 0) {
start = System.nanoTime();
} else {
long current = System.nanoTime();
if (current != start) {
end = current;
break;
}
}
}
System.out.println("The time interval of your OS: " + (end - start) + "ns");
}
}
结果却是:
The time interval of your OS: 763ns
奇怪,只有763ns,还不到0.0001ms呢,这是怎么回事?为什么1ms的间隔都得不到,却能得到0.0001ms的间隔?这个值不是瞎写的吧!
于是我到万能的stackoverflow上问了几个问题,得到了几位大仙们的回答,终于明白了这个问题:
明白这一点之后,我得出了以下结论:
如果我们要测量的代码运行时间很长,或者不是特别关心其准确度,可以使用System.currentTimeMillis图个方便。但如果要求很精确或者间隔很小,最好使用nanoTime。
前面提到的几个问题地址如下:
最后再想一下,System.currentTimeMillis得到不准确值,是Java的问题还是windows xp的问题?在xp上使用其它的语言(如C等),会是什么情况?
答案是,这是操作系统跟硬件的问题,与Java无关。