Java 带复位的定时器

Java 带复位的定时器,java,Java,在Java中有没有一种有效的方法来实现带有重置功能的倒计时计时器 我在事件发生时向服务器发送事件。如果一段时间内没有任何事件发生,我需要发送心跳信号,以便服务器知道我们仍然活着。事件的发送频率必须不低于每200毫秒一次 理想情况下,我会有一个倒计时计时器,设置为200毫秒。每次事件发生时,我都会将计时器重置为200毫秒。如果计时器超时,它会发送心跳并自行重置 我不想为每个计时器绑一根线,因为我可能需要几个。我不想使用Timer+TimerTask,因为每次重置都需要创建一个新的TimerTask

在Java中有没有一种有效的方法来实现带有重置功能的倒计时计时器

我在事件发生时向服务器发送事件。如果一段时间内没有任何事件发生,我需要发送心跳信号,以便服务器知道我们仍然活着。事件的发送频率必须不低于每200毫秒一次

理想情况下,我会有一个倒计时计时器,设置为200毫秒。每次事件发生时,我都会将计时器重置为200毫秒。如果计时器超时,它会发送心跳并自行重置

我不想为每个计时器绑一根线,因为我可能需要几个。我不想使用Timer+TimerTask,因为每次重置都需要创建一个新的TimerTask并将其添加到队列中。在重载情况下,我可能不得不每秒触发数千个事件,并且不想为每个事件创建TimerTask

我提出的最佳方案是使用
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(…)
并每10或20毫秒触发一次。我可以检查倒计时值,并在必要时重置它。不过,这感觉不是很有效,也不会给我一个好的计时器分辨率


有更好的方法吗?

您可以使用和滚动自己的可重置计时器

创建一个子类,覆盖
timeout()
以发送心跳消息。每次发送消息时,调用
ResettableTimer\reset()
方法重置心跳计时器


希望有帮助。

使用Executor服务是有意义的。Goetz等人认为它实际上是Java并发中util.Timer的改进

我会考虑如下的事情:

  • 具有保存最后一个事件的lastEventTime的易失性变量
  • 设置在lastEventTime+200毫秒执行的非重复TimerTask
当TimerTask发生时,如果lastEventTime过去大于200 ms,请发送ping并将lastEventTime变量更新到现在,然后创建并设置新的TimerTask,以便在新的lastEventTime+200(将来将为200 ms)时再次检查


如果在TimerTask签入时,事件在过去不到200毫秒发生(例如,过去150毫秒),请将下一个TimerTask设置为在当前lastEventTime+200(在示例中为50毫秒后)再次签入。

计时器对象一次只能运行任务,如果上一个任务需要更多的时间来完成,它会被延迟。这真的很优雅,谢谢。它确实有捆绑线程的缺点,但在其他方面效率很高。我想知道Object.wait()是如何在后台实现的,如果它在计时器计时期间执行一些处理,就像我建议的.scheduleAtFixedRate()方法一样?重新阅读您的问题,我发现您不希望每个计时器都有一个线程。您需要多个可重置的心跳计时器吗?有趣。如果是这样,您可以重新实现
run()
循环以确定下一个计时器将过期(可能使用
PriorityQueue
)和
lock.wait(下一个过期时间)
。当然,每个计时器都需要自己的
Runnable
才能在
timeout()上执行。因此,您将其拆分为多个
ResettableTimer
对象和一个
ResettableTimer.Manager
。再多做一点工作,但应该得到一个干净的、可重用的实用程序类。
public abstract class ResettableTimer implements Runnable {

    private Object lock = new Object();
    private long timeout_ms;
    private long last;

    public ResettableTimer(long timeout_ms) {
        this.timeout_ms = timeout_ms;
    }

    public void reset() {
        synchronized (lock) {
            last = System.currentTimeMillis();
            lock.notify();
        }
    }

    @Override
    public void run() {
        try {
            synchronized (lock) {
                for (;;) {
                    lock.wait(timeout_ms);
                    long delta = System.currentTimeMillis() - last;
                    if (delta >= timeout_ms) {
                        timeout();
                    }
                }
            }
        } catch (InterruptedException e) {
        }
    }

    protected abstract void timeout();
}