【发布时间】:2015-04-26 12:52:11
【问题描述】:
我正在使用 Java 执行一些任务。我有一些计时问题:我需要设置一个具有固定重复周期的计时器。我尝试了标准Timer、TimerTask 和ScheduledExecutor,但两者都以近似的方式工作,即如果我使用以下代码设置 40 毫秒的间隔(对于Executors)
m_executor = Executors.newScheduledThreadPool(5);
Runnable thread = new TheThread();
m_executor.scheduleWithFixedDelay(thread, 0, 40000000, TimeUnit.NANOSECONDS);
然后我尝试打印每次执行的“时间”
private static final class TheThread implements Runnable {
@Override
public void run() {
System.out.println(System.nanoTime()/1000000);
}
}
结果是这样的:
xxxxxx300
xxxxxx345
xxxxxx386
xxxxxx428
...
如您所见,如果我正确理解nanoTime(),函数会以随机间隔调用,接近我指定的时间间隔(40 毫秒),但不完全是我指定的时间间隔!
例如,当我使用 C 和 Win32s 时,我能够使用高度准确的 CreateTimerQueueTimer() 函数,并且每 40 毫秒调用一次回调函数:
xxxxxx300
xxxxxx340
xxxxxx380
...
我试图移动时间测量以避免打印时间。我也尝试使用scheduleAtFixedRate(),但不幸的是,周期在 35 到 47 毫秒之间变化(在方法中设置为 40)。
我想知道人们如何制作软件这样的模拟器或类似的东西,这需要一个精确的时期遵守...:-)
我想出了一个可能的解决方案,我想向您展示并询问您,专家们:) 这个想法如何适用(并且安全)
这里的问题是每 X 毫秒运行一些方法,比如 40 毫秒。这里的问题是关于 Java 计时器/计时,但是这个简单的解决方案呢?
public class MyEmulator extends Thread {
private long start = 0;
private long end = 0;
@Override
public void run() {
long exec_time;
start = System.nanoTime();
/*
* Do the emulator-loop
*/
end = System.nanoTime();
exe_time = (end - start)/1000000;
// wait with a whil() (40 - exec_time)
}
}
使用此解决方案,当我在等待 whilt() 结束后打印经过的时间时,结果正好是 40 毫秒(没有小数,这并不重要)。
你认为它是否安全,即真的是 40 毫秒?
【问题讨论】:
-
您测量
run方法执行时间的方式是错误的。您需要将其计算为current time after print statement ran - current time before print statement ran。 -
我认为这不是他想要的。他只是想记录方法运行的时间
-
您应该使用grain of salt 获取从
nanoTime()获得的值。 -
谢谢你们。嗯......我明白@bot 说什么。问题太简单了......我需要每 X 毫秒运行一次任务,必须准确!作为近似误差,1 ms 也太高了。这是因为我正在将我的模拟器从 C 移植到 Java,而我正在模拟的计算机的帧速率为 25 fps(如果它在 NTSC 中运行,则为 30 fps)。所以这种抖动对整个 cpu-loop 的影响太大了