Как мне заставить FutureTask вернуться после TimeoutException?

StackOverflow https://stackoverflow.com/questions/1281237

  •  16-09-2019
  •  | 
  •  

Вопрос

В приведенном ниже коде я улавливаю исключение TimeoutException через 100 секунд, как и предполагалось.На этом этапе я ожидаю, что код выйдет из основного режима и программа завершится, но он продолжает печатать на консоль.Как мне заставить задачу прекратить выполнение после тайм-аута?

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


}
Это было полезно?

Решение

Вам необходимо отменить задачу по тайм-ауту (и прервать ее поток).Это то что 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;
}

Другие советы

Ваш 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;
}

Уже могу сделать это благодаря звонку Thread.sleep().Дело в том, что futureTask.cancel(true) прервет другой поток, и ваш код должен отреагировать на это прерывание. Thread.sleep() делает это.Если вы не использовали Thread.sleep() или другой код прерываемой блокировки, вам придется проверить Thread.currentThread().isInterrupted() самостоятельно и как можно скорее прекратите работу (например,бросая new InterruptedException()), когда вы обнаружите, что это правда.

Вам нужно позвонить futureTask.cancel(true); из вашего обработчика исключений, чтобы отменить и прервать поток, который запускает вашу задачу.

Мой совет — узнать о механизме прерывания (это отличная статья: Работа с InterruptedException), и используйте его.

Как только вы поймали TimeoutException, вам нужно вызвать метод cancel(true) вашей задачи...

или завершите работу службы ExecutorService, вызвав ShutdownNow()...

или выйдите из виртуальной машины, вызвав System.exit(0)

в зависимости от ваших потребностей

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top