开发者

Set running time limit on a method in java

开发者 https://www.devze.com 2023-02-15 13:30 出处:网络
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 ha

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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号