我在Java中建立了一个计时循环。简单。我避免使用Thread.sleep()
,因为我的线程调度开销使不可能进行高分辨率延迟,因此我改用了以下效率极低的循环并获得了更好的结果:
public static void timerBlockingDelayTest()
{
long DELAY_TARGET = 5;
long t0, t;
t0 = System.currentTimeMillis();
while (System.currentTimeMillis() < t0+DELAY_TARGET) {}
t = System.currentTimeMillis();
long offTargetAmt = Math.abs(t-t0-DELAY_TARGET);
System.out.format("Timer loop was off target by %d milliseconds\n",
offTargetAmt);
}
我知道的事情是:操作系统不是实时的,线程调度是操作系统的一时兴起,GC可能会导致延迟。
我没有考虑什么?
在我的机器上(Windows 7 x64,i5、2.4GHz),我可以获得的最佳分辨率约为15毫秒。实际上,如果我将
DELAY_TARGET
设置为15的倍数,则效果会很好。但是,如果目标时间不在15的倍数附近,则上述offTargetAmt
通常为〜8(ms)。我也知道这篇文章:high resolution timer in java
有没有搞错?!我能做的最好的是正负约8毫秒吗?!我只是在寻找“是的”或“否,您没有考虑____”的答案。谢谢
更新:
使用System.nanoTime()似乎有很大的不同。起初我不相信,但是这里是我更新的代码,比较了这两种方法。你自己看。
public static void timerBlockingDelayTest()
{
long DELAY_TARGET_MS = 5;
long NS_PER_MS = 1000000;
long DELAY_TARGET_NS = DELAY_TARGET_MS * NS_PER_MS;
long t0, t;
// Using System.currentTimeMillis()
t0 = System.currentTimeMillis();
while (System.currentTimeMillis() < t0+DELAY_TARGET_MS) {}
t = System.currentTimeMillis();
long msOffTarget = Math.abs(t-t0-DELAY_TARGET_MS);
// Using System.nanoTime()
t0 = System.nanoTime();
while (System.nanoTime() < t0+DELAY_TARGET_NS) {};
t = System.nanoTime();
long nsOffTarget = Math.abs(t-t0-DELAY_TARGET_NS);
// Compare the two methods
System.out.format("System.currentTimeMillis() method: ");
System.out.format(" - Off by %d ms (%d ns) \n",
msOffTarget, msOffTarget*NS_PER_MS);
System.out.format("System.nanoTime() method: ");
System.out.format(" - Off by %d ms (%d ns)\n",
nsOffTarget/NS_PER_MS, nsOffTarget);
}
这是一个示例输出:
debug:
System.currentTimeMillis() method: - Off by 11 ms (11000000 ns)
System.nanoTime() method: - Off by 0 ms (109 ns)
BUILD SUCCESSFUL (total time: 0 seconds)
更新2(希望是最后一个):
咄。仅仅测量量化的或不完美的时间函数的性能有点愚蠢。我的意思是,我实际上是在单独测量currentTimeMillis()的性能,这并不是我做过的最聪明的事情。在意识到这一点之后,我介绍了上述两种方法,并发现nanoTime()确实产生了更好的分辨率。
如果没有分析器,请使用nanoTime()来测量currentTimeMillis()循环的持续时间,如下所示:
public static void timerBlockingDelayTest()
{
long DELAY_TARGET_MS = 5;
long NS_PER_MS = 1000000;
long DELAY_TARGET_NS = DELAY_TARGET_MS * NS_PER_MS;
long t0ms, t0, t;
// Using System.currentTimeMillis()
t0 = System.nanoTime();
t0ms = System.currentTimeMillis();
while (System.currentTimeMillis() < t0ms+DELAY_TARGET_MS) {}
t = System.nanoTime();
long nsOffTarget1 = Math.abs(t-t0-DELAY_TARGET_NS);
// Using System.nanoTime()
t0 = System.nanoTime();
while (System.nanoTime() < t0+DELAY_TARGET_NS) {};
t = System.nanoTime();
long nsOffTarget2 = Math.abs(t-t0-DELAY_TARGET_NS);
// Compare the two methods
System.out.format("System.currentTimeMillis() method: ");
System.out.format(" - Off by %d ms (%d ns)\n",
nsOffTarget1/NS_PER_MS, nsOffTarget1);
System.out.format("System.nanoTime() method: ");
System.out.format(" - Off by %d ms (%d ns)\n",
nsOffTarget2/NS_PER_MS, nsOffTarget2);
}
至少以这种方式,我通过相同的参考来测量两个延迟,这只是稍微聪明一点。上面给出了这样的输出:
debug:
System.currentTimeMillis() method: - Off by 4 ms (4040402 ns)
System.nanoTime() method: - Off by 0 ms (110 ns)
BUILD SUCCESSFUL (total time: 0 seconds)
结论:使用nanoTime(),祝您生活愉快。
最佳答案
使用System.nanoTime代替。有关nanoTime和currentTimeMillis之间的区别,请参见this answer。
关于java - 是否有可能使该Java计时器具有优于〜15 ms的分辨率?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25342872/