调用Thread.sleep()后,System.nanoTime()测量经过的时间的准确度会降低

我在这里遇到一个非常不寻常的问题。 似乎调用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 Horizo​​n,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()在每次迭代中rest一下。 我想从运行搜索所花费的总时间中排除hibernate时间,因此我使用System.nanoTime()来记录开始和结束时间。 但是,如上所述,这不起作用。

有办法解决这个问题吗?

谢谢你的任何输入!

这是一个复杂的主题,因为JVM使用的定时器高度依赖CPU和OS,并且随Java运行时版本而变化。 VM还可能限制它们传递给guest虚拟机的CPUfunction,这可能会改变相对于裸机设置的选择。

您可能需要阅读以下内容,但请注意,其中一些文章可能有点过时,多年来TSC可靠性有了很大提高:

在linux上你应该检查tsc相关的/proc/cpuinfo标志和选中的/sys/devices/system/clocksource/*/current_clocksource

我可以建议至少两种可能的原因:

  1. 省电。 执行busy循环时,CPU以其最高性能状态运行。 但是,在Thread.sleep之后,它可能会进入节能状态之一 ,频率和电压会降低。 在CPU不会立即恢复到最大性能之后,这可能需要几纳秒到几微秒。
  2. 调度。 由于Thread.sleep导致线程被调度后,它将在计时器事件之后再次执行,这可能与用于System.nanoTime的计时器有关。

在这两种情况下,您无法直接解决这个问题 – 我的意思是Thread.sleep也会影响您的实际应用程序中的计时。 但是,如果测量的有用工作量足够大,则不准确性可以忽略不计。

不一致可能不是来自Java,而是来自不同的操作系统和虚拟机“primefaces”或系统时钟本身。

根据官方.nanoTime()文档:

除了分辨率至少与currentTimeMillis()的分辨率一样好之外,不做任何保证

资源

…我可以从个人的角度知道这是因为在某些操作系统和虚拟机中,系统本身不支持“primefaces”时钟,后者是更高分辨率所必需的。 (我会在发现它后立即发布链接以获取此信息……已经很长时间了。)