Java 带复位的定时器
在Java中有没有一种有效的方法来实现带有重置功能的倒计时计时器 我在事件发生时向服务器发送事件。如果一段时间内没有任何事件发生,我需要发送心跳信号,以便服务器知道我们仍然活着。事件的发送频率必须不低于每200毫秒一次 理想情况下,我会有一个倒计时计时器,设置为200毫秒。每次事件发生时,我都会将计时器重置为200毫秒。如果计时器超时,它会发送心跳并自行重置 我不想为每个计时器绑一根线,因为我可能需要几个。我不想使用Timer+TimerTask,因为每次重置都需要创建一个新的TimerTask并将其添加到队列中。在重载情况下,我可能不得不每秒触发数千个事件,并且不想为每个事件创建TimerTask 我提出的最佳方案是使用Java 带复位的定时器,java,Java,在Java中有没有一种有效的方法来实现带有重置功能的倒计时计时器 我在事件发生时向服务器发送事件。如果一段时间内没有任何事件发生,我需要发送心跳信号,以便服务器知道我们仍然活着。事件的发送频率必须不低于每200毫秒一次 理想情况下,我会有一个倒计时计时器,设置为200毫秒。每次事件发生时,我都会将计时器重置为200毫秒。如果计时器超时,它会发送心跳并自行重置 我不想为每个计时器绑一根线,因为我可能需要几个。我不想使用Timer+TimerTask,因为每次重置都需要创建一个新的TimerTask
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(…)
并每10或20毫秒触发一次。我可以检查倒计时值,并在必要时重置它。不过,这感觉不是很有效,也不会给我一个好的计时器分辨率
有更好的方法吗?您可以使用和滚动自己的可重置计时器 创建一个子类,覆盖
timeout()
以发送心跳消息。每次发送消息时,调用ResettableTimer\reset()
方法重置心跳计时器
希望有帮助。使用Executor服务是有意义的。Goetz等人认为它实际上是Java并发中util.Timer的改进 我会考虑如下的事情:
- 具有保存最后一个事件的lastEventTime的易失性变量
- 设置在lastEventTime+200毫秒执行的非重复TimerTask
如果在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();
}