I have a method that returns a String.
Is it possible that开发者_StackOverflow中文版 after a certain time, if threshold is excedeed for that method, to return some specific string?
The Guava library has a very nice TimeLimiter
that lets you do this on any method that's defined by an interface. It can generate a proxy for your object that has a "built-in" timeout.
I did something similar in the past when spawning an external process with Runtime.getRuntime().exec(command)
. I think you could do something like this within your method:
Timer timer = new Timer(true);
InterruptTimerTask interruptTimerTask = new InterruptTimerTask(Thread.currentThread());
timer.schedule(interruptTimerTask, waitTimeout);
try {
// put here the portion of code that may take more than "waitTimeout"
}
catch (InterruptedException e) {
log.error("timeout exeeded");
}
finally {
timer.cancel();
}
and here is InterruptTimerTask
/*
* A TimerTask that interrupts the specified thread when run.
*/
protected class InterruptTimerTask extends TimerTask {
private Thread theTread;
public InterruptTimerTask(Thread theTread) {
this.theTread = theTread;
}
@Override
public void run() {
theTread.interrupt();
}
}
As answered of @MarcoS
I found timeout is not raised if method is locking something and not release cpu time to Timer. Then Timer cannot start new thread. So I change a bit by start Thread immediately and sleep inside thread.
InterruptTimerTaskAddDel interruptTimerTask = new InterruptTimerTaskAddDel(
Thread.currentThread(),timeout_msec);
timer.schedule(interruptTimerTask, 0);
/*
* A TimerTask that interrupts the specified thread when run.
*/
class InterruptTimerTaskAddDel extends TimerTask {
private Thread theTread;
private long timeout;
public InterruptTimerTaskAddDel(Thread theTread,long i_timeout) {
this.theTread = theTread;
timeout=i_timeout;
}
@Override
public void run() {
try {
Thread.currentThread().sleep(timeout);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace(System.err);
}
theTread.interrupt();
}
}
You can use AOP and a @Timeable
annotation from jcabi-aspects (I'm a developer):
@Timeable(limit = 1, unit = TimeUnit.SECONDS)
String load(String resource) {
while (true) {
if (Thread.currentThread.isInterrupted()) {
throw new IllegalStateException("time out");
}
// execution as usual
}
}
When time limit is reached your thread will get interrupted()
flag set to true
and it's your job to handle this situation correctly and to stop execution.
Also, check this blog post: http://www.yegor256.com/2014/06/20/limit-method-execution-time.html
Here is an example using Guava SimpleTimeLimiter
import com.google.common.util.concurrent.SimpleTimeLimiter;
import com.google.common.util.concurrent.TimeLimiter;
import java.time.Duration;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;
class TimeoutExample {
public static void main(String[] args) throws InterruptedException, TimeoutException, ExecutionException {
TimeLimiter timeLimiter = SimpleTimeLimiter.create(Executors.newSingleThreadExecutor());
Duration timeout = Duration.ofMillis(500);
String result = timeLimiter.callWithTimeout(() -> possiblyLongMethod(100), timeout); // will return
System.out.println(result);
String result2 = timeLimiter.callWithTimeout(() -> possiblyLongMethod(1000), timeout); // will timeout
System.out.println(result2);
}
public static String possiblyLongMethod(int runtime) throws InterruptedException {
Thread.sleep(runtime);
return "Ran for " + runtime + "ms";
}
}
The first call will return sucessfully as the call only takes 100ms, but the second will fail with a TimeoutException
as it would take 1000ms
精彩评论