开发者社区> 问答> 正文

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执行完,顺序不满足预期,前辈有什么好办法呢?

"

展开
收起
因为相信,所以看见。 2020-05-27 10:02:16 1467 0
1 条回答
写回答
取消 提交回答
  • 阿里,我所有的向往

    "

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

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

    }

    ######

    我们写一个有超时功能的 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)

    "
    2020-05-27 17:35:52
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
Spring Cloud Alibaba - 重新定义 Java Cloud-Native 立即下载
The Reactive Cloud Native Arch 立即下载
JAVA开发手册1.5.0 立即下载