【问题标题】:How to call a method at exactly the same interval of time in a loop?如何在循环中以完全相同的时间间隔调用方法?
【发布时间】:2014-01-03 22:14:57
【问题描述】:

在 Java 中,我有一个调用方法的循环,然后该方法有一个 sin,它将自程序执行以来的时间作为参数。该循环以每秒 60 次恒定更新运行(预期变化为 +-1 或 2 次以上)。我想做的是在该循环中调用一个方法,但是该方法必须每 0.2、0.4... 秒(固定间隔)调用一次,所以我所做的是: if(executionTime % 200 == 0) 但这还不够,因为它并不总是准确的,所以它跳过了很多次。为此,我尝试if(executionTime % 200 <= 50) 尝试限制它,但它仍然跳过了几次,但比以前少了。所以我的问题是,是否有任何方法可以让它在 0.2 秒内准确运行,并提供以下详细信息:

  • 如果循环一次迭代的时间超过 0.2 秒,则调用该方法。
  • 如果不到 0.2 秒,我不确定,因为如果是 30 毫秒,那么显然不是,但如果是 198 毫秒,那么是的,在很小的范围内。

我正在使用它来调用 sin ,每次调用该方法时该变量都会递增一些数字(这是必须每 200 毫秒调用一次该方法的地方)。本质上,我想做一些类似于绘制一个依赖于时间(X)的函数的事情,其中​​ X 每 200 毫秒循环迭代增加相同的数字。因此,每次循环迭代,每 200 毫秒计算一次图的新点。我可以做的是在每次调用循环中的其他方法之前检查是否该调用此方法,但这会破坏循环的顺序。我四处搜索,但我只能找到调度,我认为这不会这样做。

编辑:伪代码:

int increment;

while(running){
    first();
    second();

    if(condition)
        doSomething();
    if(timeCheck) // time check every 200ms; this is what I don't know how to do
        graphfunction(increment);
}

【问题讨论】:

  • 你试过线程吗?在此处粘贴您的代码..
  • 我没有尝试过 Thread,因为我还不熟悉它的线程,但是由于线程可能不会并行运行,这不会让它变得不可预测吗?
  • 删除 50% 的文本并将其替换为循环的实际代码。
  • 为什么不只是if (200 - exceutionTime > 0) { Thread.sleep(200 - exceutionTime) }
  • @MarkoTopolnik 我一直在从 C++ 切换到 Java,还没有真正的代码,但我会写一个伪代码。

标签: java time fixed


【解决方案1】:

我会使用java.util.concurrentExecutorService。看看Javadoc。在该对象上使用以下方法

ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) 

Javadoc:

创建并执行首先启用的周期性操作 在给定的初始延迟之后,随后在给定的时间段内; 也就是说,执行将在 initialDelay 之后开始 initialDelay+period,然后是 initialDelay + 2 * period,以此类推。

【讨论】:

  • 谢谢,它可以工作,但是有什么方法可以更好地控制它,因为它会自动运行。比如启动它,停止它,给Runnable命令添加参数,因为它不是很灵活。
  • 实际上,我创建了一个实现 Runnable 的新类并让它接受参数。谢谢。
【解决方案2】:

你正在做一些图形化的事情,可能是为了 Swing GUI。使用swing Timer,而不是循环。这是最优的。如果计算时间过长,丢弃一帧:检查定时器回调进行计算,是否还没有进行先前的计算。

其实如果你在timer回调上显示上一次计算的计算结果repaint/repaintImmediately,然后再开始下一次计算,就尽可能的保持帧率准确。

也许使用双缓冲:

BufferedImage actualShown = new BufferedImage(...);

// Could be local to graphfunction:
BufferedImage beingCalculated = new BufferedImage(...);

@Override
public void repaintComponent(Graphics g) { // Called via repaint
    g.drawImage(actualShown, 0, 0);
}

void graphfunction(int increment) {
    // First draw old frame:
    repaint();

    // Calculations:
    ... beingCalculation.setRGB(x, y, Color.BLACK);

    // Double buffering:
    BufferedImage next = actualShown;
    actualShown = beingCalculated;
    beingCalculated = next;
} 

【讨论】:

  • 这似乎是一个不错的选择,我会尝试实现它,谢谢。
【解决方案3】:

你可以使用 Thread.sleep()

    long time1 ,time2;
    while (true) {
        time1 = System.currentTimeMillis();
        yourMethod();
        time2 = System.currentTimeMillis();
        if((time2-time1) <200)
        Thread.sleep(200-(time2-time1)); 

    }

【讨论】:

  • 这将花费超过 200 毫秒的循环时间,因为 yourMethod() 不会立即返回(是吗?),所以 Thread.sleep(200) 只会在 yourMethod() 完成执行后被调用。
  • 这行得通,谢谢。然而,它没有考虑循环的其余部分,只休眠该方法所需的时间,循环的其余部分比这更重要。还有,不应该是Thread.sleep(200-(time2-time1));
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 2017-12-26
  • 1970-01-01
  • 1970-01-01
  • 2018-08-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多