Tengo un método que devuelve un List
futuro
List<Future<O>> futures = getFutures();
Ahora quiero esperar hasta que todos los futuros se terminen de procesar con éxito o cualquiera de las tareas cuyo resultado sea devuelto por un futuro arroje una excepción. Incluso si una tarea arroja una excepción, no tiene sentido esperar a los otros futuros.
Un enfoque simple sería
wait() {
For(Future f : futures) {
try {
f.get();
} catch(Exception e) {
//TODO catch specific exception
// this future threw exception , means somone could not do its task
return;
}
}
}
Pero el problema aquí es si, por ejemplo, el 4to futuro arroja una excepción, entonces esperaré innecesariamente a que estén disponibles los primeros 3 futuros.
¿Cómo resolver esto? ¿La cuenta regresiva ayudará con el pestillo de alguna manera? No puedo usar Future isDone
porque el documento de Java dice
boolean isDone()
Returns true if this task completed. Completion may be due to normal termination, an exception, or cancellation -- in all of these cases, this method will return true.
java
multithreading
future
usuario93796
fuente
fuente
ExecutionService
cada "lote" de tareas, enviarlas a él, luego inmediatamente cerrar el servicio y usarloawaitTermination()
, supongo.CountDownLatch
si envolviste el cuerpo de todos tus futuros en unatry..finally
para asegurarte de que el pestillo también se reduzca.Respuestas:
Puede usar un Servicio de finalización para recibir los futuros tan pronto como estén listos y si uno de ellos arroja una excepción, cancele el procesamiento. Algo como esto:
Creo que puede mejorar aún más para cancelar cualquier tarea que aún se esté ejecutando si uno de ellos arroja un error.
fuente
CompletionService
.Si está utilizando Java 8 , puede hacerlo más fácilmente con CompletableFuture y CompletableFuture.allOf , que aplica la devolución de llamada solo después de completar todos los CompletableFutures suministrados.
fuente
Future
instancias, no puede aplicar este método. No es fácil de convertirFuture
enCompletableFuture
.Use a
CompletableFuture
en Java 8fuente
Puede usar un ExecutorCompletionService . La documentación incluso tiene un ejemplo para su caso de uso exacto:
Lo importante a tener en cuenta aquí es que ecs.take () obtendrá la primera tarea completada , no solo la primera enviada. Por lo tanto, debe obtenerlos en el orden de terminar la ejecución (o lanzar una excepción).
fuente
Si está utilizando Java 8 y no desea manipular
CompletableFuture
s, he escrito una herramienta para recuperar resultados para unaList<Future<T>>
transmisión de uso. La clave es que tienes prohibido hacerlomap(Future::get)
mientras se lanza.Esto necesita un
AggregateException
que funcione como C #Este componente actúa exactamente como la tarea de C # .WaitAll . Estoy trabajando en una variante que hace lo mismo que
CompletableFuture.allOf
(equivalente aTask.WhenAll
)La razón por la que hice esto es porque estoy usando Spring's
ListenableFuture
y no quiero portarlo aCompletableFuture
pesar de que es una forma más estándarfuente
En caso de que desee combinar una Lista de CompletableFutures, puede hacer esto:
Para obtener más detalles sobre Future & CompletableFuture, enlaces útiles:
1. Future: https://www.baeldung.com/java-future
2. CompletableFuture: https://www.baeldung.com/java-completablefuture
3. CompletableFuture: https : //www.callicoder.com/java-8-completablefuture-tutorial/
fuente
tal vez esto ayudaría (¡nada se reemplazaría con un hilo sin procesar, sí!) Sugiero ejecutar a cada
Future
chico con un hilo separado (van paralelos), luego, cuando uno de los errores recibidos, solo indica al gerente (Handler
clase).Tengo que decir que el código anterior sería un error (no se verificó), pero espero poder explicar la solución. por favor inténtalo
fuente
fuente
CompletionService tomará sus Callables con el método .submit () y puede recuperar los futuros calculados con el método .take ().
Una cosa que no debe olvidar es terminar el ExecutorService llamando al método .shutdown (). Además, solo puede llamar a este método cuando haya guardado una referencia al servicio del ejecutor, así que asegúrese de mantener una.
Código de ejemplo: para un número fijo de elementos de trabajo para trabajar en paralelo:
Código de ejemplo: para un número dinámico de elementos de trabajo para trabajar en paralelo:
fuente
Tengo una clase de utilidad que contiene estos:
Una vez que tenga eso, utilizando una importación estática, puede simplemente esperar todos los futuros como este:
También puede recopilar todos sus resultados de esta manera:
Solo volví a visitar mi antigua publicación y me di cuenta de que tenías otro dolor:
En este caso, la solución simple es hacer esto en paralelo:
De esta manera, la primera excepción, aunque no detendrá el futuro, romperá la declaración forEach, como en el ejemplo en serie, pero como todos esperan en paralelo, no tendrá que esperar a que se completen los primeros 3.
fuente
fuente