hilos - Ejecutores Java: ¿cómo puedo detener las tareas enviadas?
pool de hilos java (5)
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).
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ónInterruptedException
, asegúrese de salir con gracia 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<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 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<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);
}
}
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
Ponga el fut.cancel(true);
en el bloque finalmente
fut.get () es una llamada de bloqueo, 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 usando 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 pila completo, en lugar del error de una línea.