我在这里遇到了一个非常不寻常的问题。似乎调用了Thread.sleep(n),其中n> 0将导致以下System.nanoTime()调用不太可预测。
以下代码说明了这个问题。
在我的电脑上运行它(rMBP 15" 2015,OS X 10.11,jre 1.8.0_40-b26)输出以下结果:
Control: 48497
Random: 36719
Thread.sleep(0): 48044
Thread.sleep(1): 832271
在运行Windows 8的虚拟机上(VMware Horizon,Windows 8.1,为1.8.0_60-b27):
Control: 98974
Random: 61019
Thread.sleep(0): 115623
Thread.sleep(1): 282451
但是,在企业服务器上运行它(VMware,RHEL 6.7,jre 1.6.0_45-b06):
Control: 1385670
Random: 1202695
Thread.sleep(0): 1393994
Thread.sleep(1): 1413220
令人惊讶的是我期望的结果。
显然Thread.sleep(1)会影响下面代码的计算。我不知道为什么会这样。有没有人有线索?
谢谢!
public class Main {
public static void main(String[] args) {
int N = 1000;
long timeElapsed = 0;
long startTime, endTime = 0;
for (int i = 0; i < N; i++) {
startTime = System.nanoTime();
//search runs here
endTime = System.nanoTime();
timeElapsed += endTime - startTime;
}
System.out.println("Control: " + timeElapsed);
timeElapsed = 0;
for (int i = 0; i < N; i++) {
startTime = System.nanoTime();
//search runs here
endTime = System.nanoTime();
timeElapsed += endTime - startTime;
for (int j = 0; j < N; j++) {
int k = (int) Math.pow(i, j);
}
}
System.out.println("Random: " + timeElapsed);
timeElapsed = 0;
for (int i = 0; i < N; i++) {
startTime = System.nanoTime();
//search runs here
endTime = System.nanoTime();
timeElapsed += endTime - startTime;
try {
Thread.sleep(0);
} catch (InterruptedException e) {
break;
}
}
System.out.println("Thread.sleep(0): " + timeElapsed);
timeElapsed = 0;
for (int i = 0; i < N; i++) {
startTime = System.nanoTime();
//search runs here
endTime = System.nanoTime();
timeElapsed += endTime - startTime;
try {
Thread.sleep(2);
} catch (InterruptedException e) {
break;
}
}
System.out.println("Thread.sleep(1): " + timeElapsed);
}
}
基本上我在while循环中运行搜索,通过调用Thread.sleep()在每次迭代中休息一下。我想从运行搜索的总时间中排除休眠时间,因此我使用System.nanoTime()来记录开始和结束时间。但是,正如您在上面提到的那样,这并不能很好地发挥作用。
有没有办法解决这个问题?
感谢您的任何意见!
答案 0 :(得分:3)
这是一个复杂的主题,因为JVM使用的定时器高度依赖CPU和OS,并且随Java运行时版本而变化。虚拟机还可能限制它们传递给访客的CPU功能,这可能会改变相对于裸机设置的选择。
您可能需要阅读以下内容,但请注意,其中一些文章可能有点过时,多年来TSC的可靠性有了很大提高:
constant_tsc tsc_reliable nonstop_tsc
)UseLinuxPosixThreadCPUClocks
和AssumeMonotonicOSTimers
在linux上,你应该检查与tsc相关的/proc/cpuinfo
标志和选中的/sys/devices/system/clocksource/*/current_clocksource
答案 1 :(得分:2)
我可以至少提出两种可能的原因:
Thread.sleep
之后,它可能会落入power-saving states之一,频率和电压会降低。在CPU没有立即恢复到最大性能之后,这可能需要几纳秒到几微秒。Thread.sleep
而被调度后,在可能与定时器相关的定时器事件后,它将被安排再次执行用于System.nanoTime
。在这两种情况下,您无法直接解决此问题 - 我的意思是Thread.sleep
也会影响您的实际应用中的时间安排。但是,如果测得的有用工作量足够大,那么不准确性就可以忽略不计了。
答案 2 :(得分:0)
不一致可能不是来自Java,而是来自不同的操作系统和虚拟机“atomic - ”或系统时钟本身。
根据官方.nanoTime()
文件:
除了分辨率至少同样好之外,不做任何保证 就像currentTimeMillis()
一样
...我可以从个人的角度知道这是因为在某些操作系统和虚拟机中,系统本身不支持“原子”时钟,这是更高分辨率所必需的。 (我会在发现它后立即发布链接以获取此信息......已经很长时间了。)