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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11629267/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:51:31  来源:igfitidea点击:

How to implement a efficient timeout in java

javaoptimizationtimeouttimertask

提问by stormsam

There are nobject which perform some actions. After performing an action a timestamp will be updated. Now I want to implement a timeout-thread which verifies if a timestamp is older than for example 60 seconds.

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

My first solution was to do that with a thread (while-loop + sleep) which is holding a list with all objects including the last timestamp. Now I have the problem that there is a worst-case scenario where the thread needs 59 seconds plus sleep time to decide for a timeout.

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

I'm searching for a solution like a Timer where it is possible to update the delay time.

我正在寻找像 Timer 这样可以更新延迟时间的解决方案。

Any ideas?

有任何想法吗?

回答by Adrian Shum

I think using a monitor object with wait/notify is reasonable (you may use Condition with await/signal if you are using JDK >= 5)

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

idea is simple:

想法很简单:

Worker thread:

工作线程:

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

    jobFinishedMonitor.notify();
}

Timeout thread:

超时线程:

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

回答by maasg

For the question, it's not clear what you want to do with the timeout. Here I present you two options to implement a lightweight timeout: monitored vs controlled.

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

Monitored Timeout

监控超时

For a global timer, you can use the Timerfacility from the JDK:

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

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

There's a similar construction possible using a ScheduledExecutorService:

可以使用 a 进行类似的构造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); 

I prefer the ScheduledExecutorServiceabove the Timerfacility, as the SchedulerExecutorcan hold a pool of threads. Also, the underlying threadpool can be used for other operations invoking scheduledExecutorService.execute(...)for immediate concurrent execution (not scheduled), making it a generic executor facility, rather than a dedicated timer function.

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

In both cases, you'll need to take special care to safely get the timeout value from your the objects you are monitoring. Typically, you will use a synchronized method in the object to ask for it's timeout status.

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

Enforced Timeout

强制超时

The ExecutorService provides you with an API to execute a set of tasks within a given timeout. e.g.

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);

After this method returns, you can ask every Future whether it succeeded within the time given.

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

回答by user207421

Interrupt the thread every time you update a timestamp. Then it will loop, find nothing to do, sleep, and if nothing else has happened to the timestamp, expire it. If it gets interrupted a second time, so much the better. And at all times it should never sleep for longer than 60 minus (current time minus the oldest timestamp).

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