Pergunta

No código abaixo, eu estou pegando um TimeoutException após 100 segundos como pretendido. Neste ponto, eu esperaria o código para sair do principal e o programa para terminar, mas ele mantém a impressão para o console. Como faço para obter a tarefa de parar a execução após o tempo limite?

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


}
Foi útil?

Solução

Você precisa cancelar a sua tarefa no tempo limite (e interromper seu segmento). Isso é o que método cancel(true) é para. :

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

Outras dicas

Seu deve mobilizável para ser capaz de parar rapidamente, quando necessário.

O seu código:

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

já é capaz de fazer isso graças a chamar Thread.sleep(). Ponto é que futureTask.cancel(true) vai interromper outro segmento, e seu código precisa reagir a esta interrupção. Thread.sleep() faz isso. Se você não usar Thread.sleep() ou outro código de bloqueio de interrupção, você teria que verificar Thread.currentThread().isInterrupted() por si mesmo, e sair o mais rápido possível (por exemplo, jogando new InterruptedException()) quando você achar que isso seja verdade.

Você precisa chamar futureTask.cancel(true); do seu manipulador de exceção para cancelar e linha de interrupção que corre a sua tarefa.

O meu conselho é para aprender sobre mecanismo de interrupção (isso é ótimo artigo: Lidar com InterruptedException ), e usá-lo.

Uma vez que você pegou o TimeoutException, você precisa chamar o método cancel (true) de sua tarefa ...

ou desligar o ExecutorService chamando shutdownNow () ...

ou sair do VM chamando System.exit (0)

dependendo de suas necessidades

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top