简体   繁体   中英

How do I check if function execution takes more than specified seconds?

I want to timeout the execution of a function if it takes more than 3 seconds.

long startTime = System.currentTimeMillis();
getStaticJsonResponse("build", "post");
long finishTime = System.currentTimeMillis();
long elapsedTime = finishTime - startTime / 1000;
System.out.println("time" + elapsedTime);

You need to have a separate thread which waits for the termination of the method or the timeout. Luckily, the creators of the great Guava library have implemented this already: Just use a TimeLimiter (in your case, the SimpleTimeLimiter ).

Your code would look like this:

TimeLimiter limiter = new SimpleTimeLimiter();
String result = limiter.callWithTimeout(new Callable<String>() {
    public String call() {
      return getStaticJsonResponse("build", "post");
    }
  }, 3, TimeUnit.SECONDS, false);

(Assuming your method returns a String, otherwise adjust the return type).

Note that as with the other solutions, this guarantees that the caller will wait at most 3 seonds. It does however not guarantee that the method execution is actually aborted after 3 seconds. It is only aborted if the called code reacts to thread interrupts as done by Thread.interrupt() . All functions waiting for I/O do so, but your own code may not.

I'm not sure if I'm interpreting the question right (since the other answers suggest otherwise), but I'm gathering that you want to implement a timeout on your getStaticJsonResponse() call (which I'm assuming is a blocking network call)?

If that is indeed the case, it is no simple task - implementing a timeout on top of a synchronous API is not necessarily easy.

One approach is to use a task thread. In this case, you would create a new class something like the following:

class JSONRequester implements Runnable
{
    @Override
    public void run ( )
    {
        getStaticJsonResponse("build", "post");
    }
}

This basically just declares a class that can run your getStaticJsonResponse() on a separate thread. The original thread is then free to monitor the task thread and terminate it if it runs for too long.

To implement a timeout (of, say, 3 seconds), you could then do something like the following:

...

// Create and start the task thread.
Thread taskThread = new Thread(new JSONRequester ( ));
taskThread.start( );

// Wait 3 seconds.
sleep(3000);

// If after waiting 3 seconds the task is still running, stop it.
if (taskThread.isAlive( ))
    taskThread.interrupt( );

...

Here, the main thread starts the task thread, which in turn calls your getStaticJsonResponse() method. It then waits three seconds, and checks if the thread is still running. If the thread is running (ie getStaticJsonResponse() hasn't finished yet), it invokes the thread's interrupt() method, which causes an InterruptedException to be thrown in JSONRequester s run() method, thereby terminating the task thread.'

EDIT: I should note that this assumes a little bit about the code within getStaticJsonResponse() , particularly, that wherever the thread is blocking satisfies one of the conditions listed here for responding to the interrupt() call. However, in networking code (as this appears to be), this is usually a pretty safe assumption.

Create a Timeout class. Construct it with a parameter that represents the number of seconds you want. Give it a HasTimedOut member function. Periodically, in the function, call this member and if it returns true , return from the function.

If you want to handle scenarios where a long running task may take longer than 3 seconds and it needs to be stopped if it does, you should perform your long running task in a separate thread. The simplest way to do this is to use Java's Executor framework.

Here's a basic example of running a potentially long (infinitely long) running task in a thread and then timing it out when it has run for longer than three seconds.

public static void main(String[] args) {
    System.err.println("Start");

    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.execute(longRunningTask);
    try {
        executor.awaitTermination(3, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.err.println("Time up - finished? " + executor.isTerminated()); //false
    executor.shutdownNow(); //runnable thread will be interrupted
}

private static Runnable longRunningTask = new Runnable() {
    @Override
    public void run() {
        while (true) {
            // ... do some long running task

            //periodically check whether task should be aborted
            if (Thread.currentThread().isInterrupted()) { //triggered by executor.shutdownNow() above
                break; //stop long running task
            }
        }
    }
};

Note that this will not be exactly 3 seconds (but close enough for a basic timeout), and that in a real world scenario the check for the interrupt should really check whether some (thread-safe, ie volatile) variable has been set as well, since an interrupt could have been triggered from another thread (but that's beyond the scope of this answer).

Just change

long elapsedTime = finishTime - startTime / 1000;

to

long elapsedTime = (finishTime - startTime) / 1000;

and this should work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM