Pergunta

Eu enviei uma tarefa usando executores e eu preciso dele para parar depois de algum tempo (por exemplo, 5 minutos). Eu tentei fazer assim:

   for (Future<?> fut : e.invokeAll(tasks, 300, TimeUnit.SECONDS)) {
         try {
             fut.get(); 
         } catch (CancellationException ex) {
             fut.cancel(true);   
             tasks.clear();
         } catch(ExecutionException ex){
             ex.printStackTrace(); //FIXME: gestita con printstack       
         }
   }

Mas eu sempre recebo um erro: Eu tenho um vetor compartilhada que precisa ser modificado pelas tarefas e, em seguida, ler por um fio, e mesmo se eu parar toda a tarefa, se o tempo limite ocorre eu recebo:

Exception in thread "Thread-1" java.util.ConcurrentModificationException

Há algo de errado? Como posso parar as tarefas submetidas que ainda estão a trabalhar depois de 5 minutos?

Foi útil?

Solução

Só porque você chama cancel() em Future não significa que a tarefa será interrompida automaticamente. Você tem que fazer algum trabalho dentro da tarefa para se certificar de que ele irá parar:

  • Use cancel(true) para que uma interrupção é enviada para a tarefa.
  • InterruptedException Handle. Se uma função em sua tarefa lança uma InterruptedException, certifique-se de sair normalmente o mais rápido possível após a captura a exceção.
  • Thread.currentThread().isInterrupted() verificar periodicamente se a tarefa faz computação contínua.

Por exemplo:

class LongTask implements Callable<Double> {
    public Double call() {

         // Sleep for a while; handle InterruptedException appropriately
         try {
             Thread.sleep(10000);
         } catch (InterruptedException ex) {
             System.out.println("Exiting gracefully!");
             return null;
         }


         // Compute for a while; check Thread.isInterrupted() periodically
         double sum = 0.0;
         for (long i = 0; i < 10000000; i++) {
             sum += 10.0
             if (Thread.currentThread().isInterrupted()) {
                 System.out.println("Exiting gracefully");
                 return null;
             }
         }

         return sum;
    } 
}

Além disso, como outras Amarrar mencionados: ConcurrentModificationException pode ser jogado mesmo se usando a classe Vector thread-safe, porque iterators você obter do Vector não são thread-safe, e, portanto, precisam ser sincronizados. Os avançados para-loop for usa iteradores, por isso esteja atento:

final Vector<Double> vector = new Vector<Double>();
vector.add(1.0);
vector.add(2.0);

// Not thread safe!  If another thread modifies "vector" during the loop, then
// a ConcurrentModificationException will be thrown.
for (Double num : vector) {
    System.out.println(num);
}

// You can try this as a quick fix, but it might not be what you want:
synchronized (vector) {    // "vector" must be final
    for (Double num : vector) {
        System.out.println(num);
    }
}

Outras dicas

O ConcurrentModificationException está vindo de sua chamada para tasks.clear() enquanto seus Exceutors está interagindo sobre o seu tasks Vector. O que você pode tentar fazer é chamar shutdownNow() em seu ExecutorService

O caso mais comum para ConcurrentModificationException é quando o vector está sendo modificado ao mesmo tempo em que está sendo iterado. Muitas vezes, isso será feito em um único segmento. Você precisa manter um bloqueio no Vector para toda a iteração (e cuidado para não impasse).

fut.get () é uma chamada de bloqueio, mesmo após o tempo limite, você irá bloquear até que a tarefa é feita. Se você quer parar tão perto da marca de 5 minutos quanto possível, você precisa verificar o flag de interrupção, eu só recomendo que você fazê-lo usando o método Thread.isInterrupted () que preserva o estado de interrupção. Se você quer apenas parada imediatamente e não precisa limpar todo o estado, em seguida, lançar uma exceção que será pego pelo Futuro e indicado para você como um ExecutionException.

fut.cancel (true) não faz nada como o invokeAll () método já fez isso por você.

A menos que você use as "tarefas" Coleção em outro lugar, você provavelmente não precisará chamar clear () nele. Esta não vai ser a fonte do problema já que o método invokeAll () é feito com a lista pelo tempo que você chamar clear (). Mas, se você precisa para começar a formar uma lista de novas tarefas para executar, eu sugiro que você formar uma nova lista de tarefas, não usar um velho Lista de novas tarefas.

Infelizmente, eu não tenho uma resposta para o seu problema. Não vejo informação suficiente aqui para diagnosticá-la. Nada no trecho de código que você forneceu indica um uso impróprio (somente desnecessário) de biblioteca de classes / métodos. Talvez se você incluiu um rastreamento de pilha completo, em vez do erro linha um.

Coloque o fut.cancel(true); no bloco finally

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