【问题标题】:How to implement a efficient timeout in java如何在java中实现有效的超时
【发布时间】:2012-07-24 10:49:45
【问题描述】:

n 对象执行一些操作。执行操作后,时间戳将被更新。现在我想实现一个超时线程来验证时间戳是否早于例如 60 秒。

我的第一个解决方案是使用一个线程(while-loop + sleep)来做到这一点,该线程包含一个包含所有对象的列表,包括最后一个时间戳。现在我遇到的问题是,在最坏的情况下,线程需要 59 秒加上睡眠时间来决定超时。

我正在寻找一种解决方案,例如可以更新延迟时间的计时器。

有什么想法吗?

【问题讨论】:

  • 我很难理解你的逻辑。您能否展示您正在尝试做的示例代码?
  • 某事让我觉得您想监视一些线程以查找“工作完成”事件。为此,您可以使用CountDownLatch
  • 当一个对象及时完成时会发生什么?当他们不这样做时会发生什么?你允许他们继续吗?还是他们需要停下来?有几种选择。你能把你的目标添加到问题中吗?你可能会得到最适合这个问题的方法。
  • 另一个澄清:当你说“有 n 个对象执行某些操作......”我猜你的意思是“n 个线程......”?

标签: java optimization timeout timertask


【解决方案1】:

我认为使用带有等待/通知的监视器对象是合理的(如果您使用 JDK >= 5,则可以使用带有等待/信号的条件)

想法很简单:

工作线程:

doYourActualWork();
synchronized(jobFinishedMonitor) {
    updateTimestamp();

    jobFinishedMonitor.notify();
}

超时线程:

synchronized(jobFinishedMonitor) {
    while(within60Second(timestamp)) {
        jobFinishedMonitor.wait(60);
    }
    if (within60Second(timestamp)) {
        timeoutHappened=true;
    }
 }
 if (timeoutHappened) {
     // do timeout handling
 }

【讨论】:

  • 应该等待(60_000) 60 秒
【解决方案2】:

对于这个问题,不清楚你想用超时做什么。在这里,我向您展示了实现轻量级超时的两个选项:受监控的与受控的。

监控超时

对于全局计时器,您可以使用 JDK 中的 Timer 工具:

public TimeoutTask implements TimerTask {
    List<MonitorableObject>  objects;
    public TimeoutTask(List<MonitorableObject> objects) {
        // make sure you can share this collection concurrently, 
        // e.g. copyonwritearraylist
        this.objects = objects;
    }
    public void run() {
       // objects -> filter(isTimeOut(currentTime)) -> do something
    }
}

Timer timer = new Timer();
timer.schedule(new TimeoutTask(myObjectList), 0,60*1000); // repeat each 60secs

使用ScheduledExecutorService 可以进行类似的构造:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
// Note that I can use here TimeoutTask b/c TimerTask is a Runnable - 
// this is just for the example. You'd better implement a plain runnable.
scheduler.schedule(new TimeoutTask(myObjectList), 60, TimeUnit.SECONDS); 

我更喜欢ScheduledExecutorService 上面的Timer 设施,因为SchedulerExecutor 可以容纳一个线程池。此外,底层线程池可用于调用scheduledExecutorService.execute(...) 以立即并发执行(未调度)的其他操作,使其成为通用执行器工具,而不是专用计时器功能。

在这两种情况下,您都需要特别注意安全地从您正在监控的对象中获取超时值。通常,您将在对象中使用同步方法来询问它的超时状态。

强制超时

ExecutorService 为您提供了一个 API,可以在给定的超时时间内执行一组任务。例如

List<Callable<?>> myTasks = ...;
// populate myTasks with Callable`s that wrap your intended execution

ExecutorService executorService = ... ;

List<Future<?>> results = executorService.invokeAll(myTasks, 60, TimeUnit.SECONDS);

这个方法返回后,你可以在给定的时间内询问每个Future是否成功。

【讨论】:

    【解决方案3】:

    每次更新时间戳时中断线程。然后它将循环,无事可做,休眠,如果时间戳没有发生任何其他事情,则将其过期。如果它被第二次中断,那就更好了。并且在任何时候,它的睡眠时间都不应超过 60 减(当前时间减去最旧的时间戳)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-03
      • 1970-01-01
      • 2013-06-18
      • 1970-01-01
      • 2019-05-29
      • 2014-06-12
      • 2014-08-03
      • 1970-01-01
      相关资源
      最近更新 更多