Prathap
Prathap

Reputation: 1033

Time out method in java

In a java class I have a method that sometimes takes a long time for execution. Maybe it hangs in that method flow. What I want is if the method doesn't complete in specific time, the program should exit from that method and continue with the rest of flow.

Please let me know is there any way to handle this situation.

Upvotes: 6

Views: 22923

Answers (4)

Alex Pakka
Alex Pakka

Reputation: 9706

I feel the approach in accepted answer is a bit outdated. With Java8, it can be done much simpler.

Say, you have a method

MyResult conjureResult(String param) throws MyException { ... }

then you can do this (keep reading, this is just to show the approach):

private final ExecutorService timeoutExecutorService = Executors.newSingleThreadExecutor();

MyResult conjureResultWithTimeout(String param, int timeoutMs) throws Exception {
    Future<MyResult> future = timeoutExecutorService.submit(() -> conjureResult(param));
    return future.get(timeoutMs, TimeUnit.MILLISECONDS);
}    

of course, throwing Exception is bad, here is the correct extended version with proper error processing, but I suggest you examine it carefully, your may want to do some things differently (logging, returning timeout in extended result etc.):

private final ExecutorService timeoutExecutorService = Executors.newSingleThreadExecutor();

MyResult conjureResultWithTimeout(String param, int timeoutMs) throws MyException {
    Future<MyResult> future = timeoutExecutorService.submit(() -> conjureResult(param));
    try {
        return future.get(timeoutMs, TimeUnit.MILLISECONDS);
    } catch (InterruptedException e) {
        //something interrupted, probably your service is shutting down
        Thread.currentThread().interrupt();
        throw new RuntimeException(e);
    } catch (ExecutionException e) {
        //error happened while executing conjureResult() - handle it
        if (e.getCause() instanceof MyException) {
            throw (MyException)e.getCause();
        } else {
            throw new RuntimeException(e);
        }
    } catch (TimeoutException e) {
        //timeout expired, you may want to do something else here
        throw new RuntimeException(e);
    }
}

Upvotes: 0

Abax
Abax

Reputation: 1

Based on the above snipplet, I tried creating a glorified spring bean.

Such executor runs the passed limitedRuntimeTask in limited runtimeInMs. If the task finishes within its time limits, the caller continues normally in execution.

If the limitedRuntimeTask fails to finish in the defined runtimeInMs, the caller will receive the thread execution back. If a timeBreachedTask was defined, it will be executed before returning to caller.

public class LimitedRuntimeExecutorImpl {


public void runTaskInLessThanGivenMs(int runtimeInMs, final Callable limitedRuntimeTask, final Callable timeBreachedTask) {
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                LOGGER.info("Started limitedRuntimeTask");
                limitedRuntimeTask.call();
                LOGGER.info("Finished limitedRuntimeTask in time");
            } catch (Exception e) {
                LOGGER.error("LimitedRuntimeTask exception", e);
            }
        }
    });
    thread.start();

    long endTimeMillis = System.currentTimeMillis() + runtimeInMs;

    while (thread.isAlive()) {
        if (System.currentTimeMillis() > endTimeMillis) {
            LOGGER.warn("LmitedRuntimeTask did not finish in time (" + runtimeInMs + ")ms. It will run in vain.");
            if(timeBreachedTask != null ){
                try {
                    LOGGER.info("Executing timeBreachedTask");
                    timeBreachedTask.call();
                    LOGGER.info("Finished timeBreachedTask");
                } catch (Exception e) {
                    LOGGER.error("timeBreachedTask exception", e);
                }
            }
            return;
        }
        try {
            Thread.sleep(10);
        }
        catch (InterruptedException t) {}
    }

}

}

Upvotes: 0

Muhammad Imran Tariq
Muhammad Imran Tariq

Reputation: 23352

You must use threads in order to achieve this. Threads are not harmful :) Example below run a piece of code for 10 seconds and then ends it.

public class Test {
    public static void main(String args[])
        throws InterruptedException {

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("0");
                method();
            }
        });
        thread.start();
        long endTimeMillis = System.currentTimeMillis() + 10000;
        while (thread.isAlive()) {
            if (System.currentTimeMillis() > endTimeMillis) {
                System.out.println("1");
                break;
            }
            try {
                System.out.println("2");
                Thread.sleep(500);
            }
            catch (InterruptedException t) {}
        }


    }

    static void method() {
        long endTimeMillis = System.currentTimeMillis() + 10000;
        while (true) {
            // method logic
            System.out.println("3");
            if (System.currentTimeMillis() > endTimeMillis) {
                // do some clean-up
                System.out.println("4");
                return;
            }
        }
    }
}

Upvotes: 8

COD3BOY
COD3BOY

Reputation: 12092

Execute the method in a different thread, you can end a thread at anytime.

Upvotes: 1

Related Questions