9

在下面的代码中,我按预期在 100 秒后捕获了 TimeoutException。在这一点上,我希望代码从 main 退出并且程序终止,但它会继续打印到控制台。如何让任务在超时后停止执行?

private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();

private static <T> T timedCall(Callable<T> c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
    FutureTask<T> task = new FutureTask<T>(c);
    THREAD_POOL.execute(task);
    return task.get(timeout, timeUnit);
}


public static void main(String[] args) {

    try {
        int returnCode = timedCall(new Callable<Integer>() {
            public Integer call() throws Exception {
                for (int i=0; i < 1000000; i++) {
                    System.out.println(new java.util.Date());
                    Thread.sleep(1000);
                }
                return 0;
            }
        }, 100, TimeUnit.SECONDS);
    } catch (Exception e) {
        e.printStackTrace();
        return;
    }


}
4

3 回答 3

11

您需要在超时时取消任务(并中断其线程)。这就是cancel(true)方法的用途。:

private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();

private static <T> T timedCall(FutureTask<T> task, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
    THREAD_POOL.execute(task);
    return task.get(timeout, timeUnit);
}


public static void main(String[] args) {
        try {
            FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
                public Integer call() throws Exception {
                        for (int i=0; i < 1000000; i++) {
                                if (Thread.interrupted()) return 1;
                                System.out.println(new java.util.Date());
                                Thread.sleep(1000);
                        }
                        return 0;
                }
            });
            int returnCode = timedCall(task, 100, TimeUnit.SECONDS);
        } catch (Exception e) {
                e.printStackTrace();
                task.cancel(true);
        }
        return;
}
于 2009-08-15T05:59:10.537 回答
4

您的 Callable 必须能够在需要时快速停止。

你的代码:

public Integer call() throws Exception {
    for (int i=0; i < 1000000 && !task.cancelled(); i++) {
        System.out.println(new java.util.Date());
        Thread.sleep(1000); // throws InterruptedException when thread is interrupted
    }
    return 0;
}

由于 call 已经能够做到这一点Thread.sleep()。关键是futureTask.cancel(true)会中断其他线程,并且您的代码需要对这种中断做出反应。Thread.sleep()这样做。如果您没有使用Thread.sleep()或其他可中断的阻塞代码,您将不得不自己检查,并在您发现这是真的时Thread.currentThread().isInterrupted()尽快退出(例如通过抛出)。new InterruptedException()

您需要futureTask.cancel(true);从异常处理程序中调用以取消和中断运行您的任务的线程。

我的建议是了解中断机制(这是一篇很棒的文章:处理 InterruptedException)并使用它。

于 2009-08-15T06:30:32.110 回答
2

一旦你捕捉到 TimeoutException,你需要调用你的任务的 cancel(true) 方法......

或通过调用 shutdownNow() 关闭您的 ExecutorService ...

或通过调用 System.exit(0) 退出 VM

取决于你的需要

于 2009-08-15T05:51:57.070 回答