【问题标题】:Java real fixed time intervalJava真正的固定时间间隔
【发布时间】:2015-04-26 12:52:11
【问题描述】:

我正在使用 Java 执行一些任务。我有一些计时问题:我需要设置一个具有固定重复周期的计时器。我尝试了标准TimerTimerTaskScheduledExecutor,但两者都以近似的方式工作,即如果我使用以下代码设置 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 的影响太大了

标签: java timer


【解决方案1】:

我认为您无法在 Java 中以这种级别的精度来管理它。与您的 C/Win32 解决方案不同,您的 Java 解决方案在具有多个线程(不同优先级)的 JVM 中运行,并且垃圾收集正在运行并占用资源。

话虽如此,我将尝试定期执行的scheduleAtFixedRate() 方法。 scheduleWithFixedDelay() 将执行并在完成后延迟一段固定的时间。因此,不考虑您的方法实际运行所花费的时间。

【讨论】:

  • 不要忘记在 run 方法完成之前或在输入 run 方法之后打印时间,因此 OP 应该考虑打印语句和输入 /从 run 方法返回?
  • @bot,是的,你是对的,我也设置了 1 秒或 2 秒而不是毫秒,试一试。结果还是不准确。
猜你喜欢
  • 2014-02-15
  • 1970-01-01
  • 2011-06-04
  • 2013-08-20
  • 2014-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多