How to implement a efficient timeout in java

13,158

Solution 1

I think using a monitor object with wait/notify is reasonable (you may use Condition with await/signal if you are using 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
 }

Solution 2

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 Timer facility from the JDK:

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:

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 ScheduledExecutorService above the Timer facility, as the SchedulerExecutor can 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.

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.

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.

Share:
13,158
stormsam
Author by

stormsam

Updated on June 04, 2022

Comments

  • stormsam
    stormsam almost 2 years

    There are n object 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.

    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.

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

    Any ideas?