java中的超时方法

时间:2012-01-24 05:30:53

标签: java

在java类中,我有一个有时需要很长时间才能执行的方法。也许它挂在那个方法流程中。我想要的是如果方法没有在特定时间内完成,程序应退出该方法并继续其余的流程。

请让我知道有没有办法处理这种情况。

4 个答案:

答案 0 :(得分:7)

您必须使用线程才能实现此目的。线程没有害处:)下面的例子运行一段代码10秒然后结束它。

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;
            }
        }
    }
}

答案 1 :(得分:1)

在不同的线程中执行该方法,您可以随时结束一个线程。

答案 2 :(得分:0)

基于上面的小贴士,我尝试创造一个美化的春豆。

此类执行程序在有限的 runtimeInMs 中运行传递的 restrictedRuntimeTask 。 如果任务在其时间限制内完成,则调用者将继续正常执行。

如果 limitedRuntimeTask 无法在定义的 runtimeInMs 中完成, 调用者将收到线程执行回来。如果定义了timeBreachedTask, 它将在返回调用者之前执行。

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) {}
    }

}

}

答案 3 :(得分:0)

我觉得接受答案的方法有点过时了。使用Java8,可以更简单地完成它。

说,你有一个方法

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

然后你可以这样做(继续阅读,这只是为了显示方法):

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);
}    

当然,抛出异常是坏的,这是正确的扩展版本,并且有正确的错误处理,但我建议你仔细检查一下,你可能想要做一些不同的事情(记录,在扩展结果中返回超时等):

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);
    }
}