Pregunta

He enviado una tarea usando ejecutores y necesito que se detenga después de un tiempo (por ejemplo, 5 minutos). He intentado hacer así:

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

Pero siempre recibo un error: tengo un Vector compartido que debe ser modificado por las tareas y luego leído por un hilo, e incluso si detengo toda la tarea, si ocurre el tiempo de espera obtengo:

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

¿Hay algo mal? ¿Cómo puedo detener las tareas enviadas que siguen funcionando después de 5 minutos?

¿Fue útil?

Solución

El hecho de que llame a cancel () en Future no significa que la tarea se detendrá automáticamente. Debe hacer un trabajo dentro de la tarea para asegurarse de que se detendrá:

  • Use cancel (true) para que se envíe una interrupción a la tarea.
  • Manejar InterruptedException . Si una función en su tarea arroja una InterruptedException , asegúrese de salir con gracia lo antes posible al detectar la excepción.
  • Verifique periódicamente Thread.currentThread (). isInterrupted () si la tarea realiza un cálculo continuo.

Por ejemplo:

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

Además, como han mencionado otras publicaciones: ConcurrentModificationException se puede lanzar incluso si se usa la clase Vector segura para subprocesos, porque los iteradores que obtienes de Vector no es seguro para subprocesos y, por lo tanto, debe sincronizarse. El bucle avanzado utiliza iteradores, así que ten cuidado:

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

Otros consejos

La ConcurrentModificationException proviene de su llamada a task.clear () mientras su Exceutors itera sobre sus tareas Vector . Lo que puede intentar hacer es llamar a shutdownNow () en su ExecutorService

El caso más común para ConcurrentModificationException es cuando el vector se está modificando al mismo tiempo que se está iterando. A menudo esto se hará en un solo hilo. Debe mantener bloqueado el Vector durante toda la iteración (y tener cuidado de no llegar a un punto muerto).

fut.get () es una llamada de bloqueo, incluso después del tiempo de espera, bloqueará hasta que se complete la tarea. Si desea detenerse lo más cerca posible de la marca de 5 minutos, debe verificar el indicador de interrupción, solo le recomiendo que lo haga utilizando el método Thread.isInterrupted () que conserva el estado de interrupción. Si desea detenerse de inmediato y no necesita limpiar ningún estado, inicie una excepción que será detectada por el futuro y se le indicará como una ExecutionException.

fut.cancel (true) no hace nada ya que el método invokeAll () ya lo ha hecho por usted.

A menos que use las " tareas " Colección en otro lugar, probablemente no necesite llamar a clear () en ella. Este no será el origen de su problema ya que el método invokeAll () se realiza con la Lista para cuando llame a clear (). Pero, si necesita comenzar a formar una lista de nuevas tareas para ejecutar, le sugiero que forme una nueva Lista de tareas, no use una Lista de Tareas nuevas.

Desafortunadamente, no tengo una respuesta para su problema. No veo suficiente información aquí para diagnosticarlo. Nada en el fragmento de código que proporcionó indica un uso incorrecto (solo innecesario) de las clases / métodos de la biblioteca. Quizás si incluyó un seguimiento completo de la pila, en lugar del error de una línea.

Pon el fut.cancel (true); en el bloque finalmente

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top