Ejecutores Java: ¿cómo puedo detener las tareas enviadas?

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

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 obtengo un error: tengo un Vector compartido que necesita ser modificado por las tareas y luego leído por un hilo, e incluso si detengo toda la tarea, si se produce 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?

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 excepción InterruptedException , asegúrese de salir graciosamente tan pronto como sea posible al detectar la excepción.
  • Compruebe periódicamente Thread.currentThread().isInterrupted() si la tarea realiza un cálculo continuo.

Por ejemplo:

 class LongTask implements Callable { 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 puede lanzarse incluso si se usa la clase Vector segura para subprocesos, porque los iteradores que se obtienen de Vector no son seguros para subprocesos y, por lo tanto, deben sincronizarse. El for-loop avanzado usa iteradores, así que ten cuidado:

 final Vector vector = new Vector(); 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); } } 

La tasks.clear() ConcurrentModificationException proviene de su llamada a tasks.clear() mientras sus Exceutors iteran sobre sus tasks Vector . Lo que puede 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 un candado en el Vector para toda la iteración (y tenga cuidado de no estancarse).

fut.get () es una llamada de locking, incluso después del tiempo de espera, bloqueará hasta que la tarea finalice. Si desea detenerse lo más cerca posible de la marca de 5 minutos, debe verificar el indicador de interrupción, solo lo recomiendo utilizando el método Thread.isInterrupted () que preserva el estado de interrupción. Si desea detenerse inmediatamente y no necesita limpiar ningún estado, ejecute una excepción que será capturada 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 la Colección “tareas” 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 hace con la Lista cuando usted llama a clear (). Pero, si necesita comenzar a formar una lista de tareas nuevas para ejecutar, le sugiero que forme una nueva Lista de tareas, no utilice una Lista anterior de Tareas nuevas.

Lamentablemente, no tengo una respuesta para tu 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 de stack completo, en lugar del error de una línea.

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