如何在java中实现高效的超时



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

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

我正在寻找一个像定时器这样的解决方案,可以更新延迟时间。

有什么想法吗?

我认为使用带有wait/notify的监视器对象是合理的(如果您使用JDK>=5,则可以使用带有waite/signal的Condition)

想法很简单:

工作线程:

doYourActualWork();
synchronized(jobFinishedMonitor) {
    updateTimestamp();
    jobFinishedMonitor.notify();
}

超时线程:

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

对于这个问题,还不清楚您想对超时做什么。在这里,我向您介绍两种实现轻量级超时的选项:监控超时和控制超时。

监控超时

对于全局计时器,可以使用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(...)的其他操作,以便立即并发执行(未调度),使其成为通用的执行器功能,而不是专用的计时器功能。

在这两种情况下,您都需要特别小心,以安全地从您正在监视的对象中获取超时值。通常,您会在对象中使用一个synchronized方法来询问它的超时状态。

强制超时

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是否在给定的时间内成功。

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

相关内容

  • 没有找到相关文章

最新更新