Java 如何让FutureTask在TimeoutException之后返回?

Java 如何让FutureTask在TimeoutException之后返回?,java,futuretask,Java,Futuretask,在下面的代码中,我在100秒后捕捉到一个TimeoutException。此时,我希望代码从main退出,程序终止,但它会一直打印到控制台。如何使任务在超时后停止执行 private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); private static <T> T timedCall(Callable<T> c, long timeout, TimeUnit

在下面的代码中,我在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;
    }


}
private static final ExecutorService THREAD_POOL=Executors.newCachedThreadPool();
私有静态T timedCall(可调用c、长超时、TimeUnit TimeUnit)抛出InterruptedException、ExecutionException、TimeoutException{
未来任务=新的未来任务(c);
线程池执行(任务);
返回任务.get(超时,时间单位);
}
公共静态void main(字符串[]args){
试一试{
int returnCode=timedCall(新的可调用(){
公共整数调用()引发异常{
对于(int i=0;i<1000000;i++){
System.out.println(新的java.util.Date());
睡眠(1000);
}
返回0;
}
},100,时间单位为秒);
}捕获(例外e){
e、 printStackTrace();
返回;
}
}

一旦捕获到TimeoutException,您需要调用任务的cancel(true)方法

或者通过调用shutdownNow()关闭ExecutorService

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


根据您的需要

您需要在超时时取消任务(并中断其线程)。这就是
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;
}
private static final ExecutorService THREAD_POOL=Executors.newCachedThreadPool();
私有静态T timedCall(FutureTask任务、长超时、TimeUnit TimeUnit)抛出InterruptedException、ExecutionException、TimeoutException{
线程池执行(任务);
返回任务.get(超时,时间单位);
}
公共静态void main(字符串[]args){
试一试{
FutureTask task=新的FutureTask(新的可调用(){
公共整数调用()引发异常{
对于(int i=0;i<1000000;i++){
if(Thread.interrupted())返回1;
System.out.println(新的java.util.Date());
睡眠(1000);
}
返回0;
}
});
int returnCode=timedCall(任务,100,时间单位为秒);
}捕获(例外e){
e、 printStackTrace();
任务。取消(true);
}
返回;
}

您的呼叫必须能够在需要时快速停止

您的代码:

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;
}
public Integer call()引发异常{
对于(int i=0;i<1000000&&!task.cancelled();i++){
System.out.println(新的java.util.Date());
Thread.sleep(1000);//当线程被中断时抛出InterruptedException
}
返回0;
}
由于调用了
Thread.sleep()
,已经能够做到这一点。关键是
futureTask.cancel(true)
将中断其他线程,您的代码需要对此中断做出反应
Thread.sleep()。如果您没有使用
Thread.sleep()
或其他可中断的阻塞代码,您必须自己检查
Thread.currentThread().isInterrupted()
,并在发现这是真的时尽快退出(例如,通过抛出
new InterruptedException()

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


我的建议是学习中断机制(这是一篇很棒的文章:),并使用它。

!task.cancelled()应该是!正如djna最初写的,我认为使用中断会更好。首先,您的可调用代码根本不需要知道
task
。其次,当您在可调用代码中使用各种阻塞操作(如
Thread.sleep()
)时,它们不会对task.isCancelled()作出反应,但通常会对中断作出反应。因此,使用
cancel(true)
并让代码意识到中断通常是最好的方法。(你的代码也会更一般,因为中断机制在Java中被广泛使用)我想我的观点是“中断是一种合作机制。”()@Peter Nice article!我已相应地更改了答案。cleary代码未经测试<代码>任务
将在
捕获
块中未定义