How do I get FutureTask to return after TimeoutException?

家住魔仙堡 提交于 2019-11-27 02:55:47

问题


In the code below, I'm catching a TimeoutException after 100 seconds as intended. At this point I would expect the code to exit from main and the program to terminate but it keeps printing to the console. How do I get the task to stop executing after timeout?

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


}

回答1:


You need to cancel your task on timeout (and interrupt its thread). That's what cancel(true) method is for. :

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



回答2:


Your Callable must to be able to stop quickly, when needed.

Your code:

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

Is already able to do that thanks to calling Thread.sleep(). Point is that futureTask.cancel(true) will interrupt other thread, and your code needs to react to this interruption. Thread.sleep() does that. If you didn't use Thread.sleep() or other interruptible blocking code, you would have to check Thread.currentThread().isInterrupted() by yourself, and quit as soon as possible (e.g. by throwing new InterruptedException()) when you find this to be true.

You need to call futureTask.cancel(true); from your exception handler to cancel and interrupt thread which runs your task.

My advice is to learn about interruption mechanism (this is great article: Dealing with InterruptedException), and use it.




回答3:


Once you caught the TimeoutException, you need to call the cancel(true) method of your task ...

or shut down your ExecutorService by calling shutdownNow() ...

or quit the VM by calling System.exit(0)

depending on your needs



来源:https://stackoverflow.com/questions/1281237/how-do-i-get-futuretask-to-return-after-timeoutexception

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!