运行() , 等待() , 运行() , 等待() , 运行()

时间:2021-07-01 11:40:40

标签: java timer timertask

我正在寻找一些 Timer() 在给定的时间内运行一个进程,然后等待一段时间,然后重复......

Timer.scheduleAtFixedRate() 不会等待-停止-一段时间。 enter image description here

1 个答案:

答案 0 :(得分:1)

计算机没有那么准确。

因此,您想要什么并不明确(或者,如果您愿意,也不可能)。

'wait 50msec' 不太可能,但接近于它。但是,“运行 200 毫秒”,这很奇怪,而且不太可能。您可能是说:“我有一些任务,大约需要 200 毫秒”?或者你的意思是:我有一个非常快的任务。我想连续做 200 毫秒没有中断,然后停止做一段时间?这也是不可能的,但接近它的事情是可能的。或者你的意思是:我有一个需要很多秒的长时间运行的工作。我希望作业运行 200 毫秒,然后在其轨道上冻结,然后在 50 毫秒后解冻并让它继续运行,等等?这很奇怪,而且不太可能。

在 Java 或现代操作系统上的任何其他语言中“等待 50 毫秒”是一个提示。这将等待大约 50 毫秒。不完全是 50 毫秒。您需要处理“漂移”这一事实。如果您让计算机等待 50 毫秒几百万次,那么您将远不及您预期的时间。有几次可能是 51 毫秒,有时可能是 52 毫秒。

以下是您可以做的事情:

  • 除了“等待 50 毫秒”之外,您还可以“等到 X”。如果你想构建一个显示秒表的小 GUI 小部件,这是正确的答案:如果你把它写成,用伪代码:
int time = 0;
while (true) {
    String formattedTime = formatTime(time);
    renderToWidget(formattedTime);
    time++;
    Thread.sleep(1000L); // wait one second
}

以上内容完全错误。随着秒表的运行,它会越来越远。相反,您应该这样做:

private static final long NANOS_IN_SECOND = 1000000000;
...


long start = System.nanoTime();
while (true) {
    long secondsPassed = (System.nanoTime() - start) / NANOS_IN_SECOND;
    String formattedTime = formatTime(secondsPassed);
    renderToWidget(formattedTime);
    Thread.sleep(500L); // why not update a little more often?
}

另一个重要的想法是,不是“等待 50 毫秒”,而是“计算下一个唤醒时间,然后无论等待多久,直到那一刻到来”的想法更好地解决了许多问题。例如,如果您想为游戏编写一个“帧率限制器”,以便游戏不会以高于 60fps 的速度渲染帧,您可以这样做:

private static final long NANOS_PER_FRAME = 1000000000 / 60; // 60 fps
...


long now = System.nanoTime();
long done = now + NANOS_PER_FRAME;

Frame frame = renderFrame();
screen.show(frame);
long toWait = System.nanoTime() - done;
if (toWait > 0) waitNanos(toWait);

换句话说,该模型不是“等待一定时间”,而是说每 x 毫秒发生一个事件,这本质上意味着该事件有 1/x 的最大运行时间,然后您编写循环无论等待多久,如果事件运行得比这更快,它都需要等待“填满剩余部分”。

哪一个适合你?不知道 - 你的问题没有具体说明。

  • 中断长时间运行的进程

Java 没有“只是冻结线程”功能。相反,线程本身中的代码需要不时签入,然后您可以在那里冻结。例如,如果您有一个比特币矿工需要每大约 200 毫秒停止一次,那么只要需要显式等待的代码非常频繁地“签入”(在计时框架的控制下调用某些方法),就可以工作。该代码可以使用上述技术来检查是否应该进行冻结,如果应该进行,只需使用 Thread.sleep(time) 来等待您的计算状态您应该等待的时间。如果在线程中运行的代码不是您编写的,也不能由您更改,则 Java 线程不是该工作的工具。

注意:请注意 System.currentTimeMillis() 是一个棘手的问题。如果用户弄乱系统时钟,该值可能会漂移甚至倒退。如今,大多数计算机都运行时间守护程序,使时钟与某个时间服务器保持同步,但这也意味着可能会发生漂移。因此,使用 System.cTM 来衡量经过的时间是一个坏主意。