首页 > Java:如何实现代码超时功能?

Java:如何实现代码超时功能?

public static void function() {
    // 代码1
    // 代码2
    // 代码3
}

如果代码2执行时间过长则不再执行(代码2没有抛出TimeoutException,只是没按照规定时间执行完),继续执行后面的代码3该如何实现呢?

下面是代码超时功能的一种实现

   public class Timeout {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService exec = Executors.newFixedThreadPool(1);
        Callable<Integer> call = new Callable<Integer>() {
            public Integer call() throws Exception {
                Thread.sleep(1000 * 5);// 耗时操作
                return 1;
            }
        };
        try {
            Future<Integer> future = exec.submit(call);
            int ret = future.get(1000 * 1, TimeUnit.MILLISECONDS); // 任务处理超时时间设为 1 秒
            System.out.println("任务执行结果:" + ret);
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        exec.shutdown();
    }
}

但这种方法的问题是新启动了一个线程,并没有阻塞,也就是我的代码3可能先于Timeout执行完,顺序不满足预期,前辈有什么好办法呢?


我们写一个有超时功能的 Callable:

import java.util.concurrent.*;

public class TimeoutCallable<V> implements Callable<V> {

    private final Callable<V> callable;
    private final V timeoutV;
    private final long timeout;

    /**
     * 构造一个 TimeoutCallable
     *
     * @param callable 要运行的 Callable
     * @param timeout Callable 的最大运行时间
     * @param timeoutV Callable 超时的返回结果
     */
    public TimeoutCallable(Callable<V> callable, long timeout, V timeoutV) {
        this.timeout = timeout;
        this.callable = callable;
        this.timeoutV = timeoutV;
    }

    @Override
    public V call() throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<V> future = executor.submit(callable);

        V v = null;
        try {
            v = future.get(timeout, TimeUnit.MILLISECONDS);
        } catch (TimeoutException ex) {
            System.out.println("Callble 超时");
        }

        executor.shutdownNow(); // 给线程池中所有正在运行的线程发送 中断 信号

        return v != null ? v : timeoutV;
    }

}

然后试验:

import java.util.concurrent.*;

public class Test {

    public static void main(String[] args) throws Exception {

        Callable<Integer> callable = () -> {
            int N = 4;
            int sum = 0;
            for (int i = 0; i < N; i++) {
                // Thread.sleep 方法是可以响应中断的,
                // 如果你的代码需要“超时则线程结束”的效果,那么你的代码也应该要能够响应中断
                Thread.sleep(1000);
                sum += i;
            }

            return sum;
        };

        // 代码2, 代码2 运行的最长时间为 timeout
        int timeout = 3000;
        Integer timeoutValue = -1;
        TimeoutCallable<Integer> timeoutCallable = new TimeoutCallable<>(callable, timeout, timeoutValue);
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> future = executor.submit(timeoutCallable);

        Integer result = future.get();
        executor.shutdown();
        // end 代码2

        // 代码3
        if (timeoutValue.equals(result)) {
            System.out.println("--任务超时--");
        } else {
            System.out.println("任务结果:" + result);
        }
        // end 代码3
    }
}

callable 的运行时间为 4 s,但我们设置的超时时间为 3 s,所以代码运行结果就是:
(可以看到 NetBeans 给出的运行时间是 3 s)

如果我们将 timeout 改成 5000(5 s),则结果是:
(可以看到 NetBeans 给出的运行时间是 4 s)


写了个小例子,可以简单实现你的要求

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Main {

    public static void main(String[] args) throws InterruptedException {
        ExecutorService es = Executors.newFixedThreadPool(1);
        es.execute(new Runnable() {
            @Override
            public void run() {
                int count = 7;
                while (count > 0) {
                    System.out.println(1);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // 退出执行
                        System.out.println("interrupt, then quit");
                        return;
                    }
                    count--;
                }
            }
        });
        // 关闭线程池
        es.shutdown();
        // 阻塞操作,等待5s
        boolean finished = es.awaitTermination(5, TimeUnit.SECONDS);
        // 如果过了5s线程还没有完成, 强制关闭, interrupt Runnable 线程,  进入 InterruptedException 处理流程
        if (!finished) {
            es.shutdownNow();
        }
        System.out.println("task 3");
    }
}
【热门文章】
【热门文章】