Necesito ejecutar una cantidad de tareas 4 a la vez, algo como esto:
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
//...wait for completion somehow
¿Cómo puedo recibir una notificación una vez que todos estén completos? Por ahora no puedo pensar en nada mejor que configurar un contador de tareas global y disminuirlo al final de cada tarea, luego monitorear en bucle infinito este contador para convertirlo en 0; u obtener una lista de Futuros y en el monitor de bucle infinito está Hecho para todos ¿Cuáles son las mejores soluciones que no involucran bucles infinitos?
Gracias.
Long.MAX_VALUE, TimeUnit.NANOSECONDS
sea equivalente a no tener un tiempo de espera.java.util.concurrent
paquete en la sección: Para esperar "para siempre", puede usar un valor deTiming
Long.MAX_VALUE
Use un CountDownLatch :
y dentro de su tarea (adjunte en try / finally)
fuente
ExecutorService.invokeAll()
lo hace por tifuente
futures
se devuelven, las tareas no se han completado. Pueden completarse en el futuro y tendrá un enlace al resultado. Por eso se llama aFuture
. Tiene el método Future.get () , que esperará a que finalice la tarea para obtener un resultado.También puedes usar Listas de Futuros:
luego, cuando desee unirse a todos ellos, es esencialmente el equivalente de unirse a cada uno (con el beneficio adicional de que vuelve a generar excepciones de subprocesos secundarios a los principales):
Básicamente, el truco es llamar a .get () en cada Futuro uno a la vez, en lugar de llamadas de bucle infinito isDone () en (todos o cada uno). Por lo tanto, tiene la garantía de "seguir adelante" a través de este bloque tan pronto como finalice el último hilo. La advertencia es que, dado que la llamada .get () vuelve a generar excepciones, si uno de los subprocesos muere, usted podría subir de esto posiblemente antes de que los otros subprocesos hayan finalizado [para evitar esto, puede agregar un mensaje
catch ExecutionException
alrededor de la llamada get ] La otra advertencia es que mantiene una referencia a todos los subprocesos, por lo que si tienen variables locales de subprocesos, no se recopilarán hasta después de pasar este bloque (aunque es posible que pueda evitar esto, si se convirtió en un problema, eliminando El futuro está fuera de la ArrayList). Si quisieras saber qué futuro "termina primero"https://stackoverflow.com/a/31885029/32453fuente
ExecutorCompletionService.take
: stackoverflow.com/a/11872604/199364En Java8 puedes hacerlo con CompletableFuture :
fuente
ExecutorService es = Executors.newFixedThreadPool(4); List< Future<?>> futures = new ArrayList<>(); for(Runnable task : taskList) { futures.add(es.submit(task)); } for(Future<?> future : futures) { try { future.get(); }catch(Exception e){ // do logging and nothing else } }
Solo mis dos centavos. Para superar el requisito de
CountDownLatch
conocer el número de tareas de antemano, puede hacerlo a la antigua usanza de una manera simpleSemaphore
.En tu tarea solo llama
s.release()
como lo haríaslatch.countDown();
fuente
release
llamadas antes de laacquire
llamada, pero después de leer la documentación de Semaphore, veo que está bien.Un poco tarde para el juego, pero para completarlo ...
En lugar de 'esperar' a que finalicen todas las tareas, puede pensar en términos del principio de Hollywood: "no me llame, lo llamaré", cuando haya terminado. Creo que el código resultante es más elegante ...
La guayaba ofrece algunas herramientas interesantes para lograr esto.
Un ejemplo ::
Envuelva un ExecutorService en ListeningExecutorService ::
Enviar una colección de invocables para su ejecución ::
Ahora la parte esencial:
Adjunte una devolución de llamada al ListenableFuture, que puede usar para recibir notificaciones cuando se completen todos los futuros ::
Esto también ofrece la ventaja de que puede recopilar todos los resultados en un solo lugar una vez que finalice el procesamiento ...
Más información aquí.
fuente
runOnUiThread()
enonSuccess()
.La clase CyclicBarrier en Java 5 y posterior está diseñada para este tipo de cosas.
fuente
Siga uno de los siguientes enfoques.
submit
encendidoExecutorService
y verificar el estado bloqueando la llamadaget()
en elFuture
objeto como lo sugiereKiran
invokeAll()
en ExecutorServiceshutdown, awaitTermination, shutdownNow
API de ThreadPoolExecutor en la secuencia adecuadaPreguntas SE relacionadas:
¿Cómo se usa CountDownLatch en Java Multithreading?
Cómo cerrar correctamente Java ExecutorService
fuente
Aquí hay dos opciones, solo confunda cuál es la mejor opción.
Opción 1:
Opcion 2:
Aquí poniendo future.get (); en el intento de captura es buena idea ¿verdad?
fuente
Podrías envolver tus tareas en otro ejecutable, que enviará notificaciones:
fuente
completed
contador. Entonces, después de iniciarlos todos, en cada notificación, podría determinar si todas las tareas se han completado. Tenga en cuenta que es vital utilizarlotry/finally
para que se envíe una notificación finalizada (o una notificación alternativa encatch
bloque) incluso si una tarea falla. De lo contrario, esperaría para siempre.Acabo de escribir un programa de muestra que resuelve su problema. No se dio una implementación concisa, así que agregaré una. Si bien puede usar
executor.shutdown()
yexecutor.awaitTermination()
, no es la mejor práctica, ya que el tiempo que tardan los diferentes subprocesos sería impredecible.fuente
Solo para proporcionar más alternativas aquí diferentes para usar pestillos / barreras. También puede obtener los resultados parciales hasta que todos terminen con CompletionService .
Desde Java Concurrency en la práctica: "Si tiene que enviar un lote de cálculos a un Ejecutor y desea recuperar sus resultados a medida que estén disponibles, puede retener el Futuro asociado con cada tarea y sondear repetidamente su finalización llamando a get with a tiempo de espera cero. Esto es posible, pero tedioso . Afortunadamente hay una mejor manera : un servicio de finalización ".
Aquí la implementación
fuente
Esta es mi solución, basada en la sugerencia "AdamSkywalker", y funciona
fuente
Podrías usar este código:
fuente
Creé el siguiente ejemplo de trabajo. La idea es tener una manera de procesar un grupo de tareas (estoy usando una cola como ejemplo) con muchos subprocesos (determinado programáticamente por el número de tareas / umbral) y esperar hasta que todos los subprocesos se completen para continuar con algún otro procesamiento.
¡Espero eso ayude!
fuente
Puede usar su propia subclase de ExecutorCompletionService para envolver
taskExecutor
y su propia implementación de BlockingQueue para informarse cuando cada tarea se complete y realizar cualquier devolución de llamada u otra acción que desee cuando el número de tareas completadas alcance su objetivo deseado.fuente
deberías usar
executorService.shutdown()
yexecutorService.awaitTermination
método.Un ejemplo de la siguiente manera:
fuente
Así que publico mi respuesta de la pregunta vinculada aquí, en caso de que alguien quiera una forma más sencilla de hacer esto
fuente
Java 8: podemos utilizar la API de transmisión para procesar la transmisión. Por favor, vea el fragmento a continuación
fuente
Si
doSomething()
lanzo algunas otras excepciones,latch.countDown()
parece que no se ejecutará, ¿qué debo hacer?fuente
si utiliza más hilos ExecutionServices SECUENCIALMENTE y desea esperar CADA SERVICIO DE EJECUCIÓN para finalizar. La mejor manera es como a continuación;
fuente
Esto puede ayudar
fuente
Puede llamar a waitTillDone () en esta clase Runner :
Puede reutilizar esta clase y llamar a waitTillDone () tantas veces como desee antes de llamar a shutdown (), además su código es extremadamente simple . Además , no tiene que saber la cantidad de tareas por adelantado.
Para usarlo solo agregue este gradle / maven
compile 'com.github.matejtymes:javafixes:1.3.1'
dependencia de a su proyecto.Más detalles se pueden encontrar aquí:
https://github.com/MatejTymes/JavaFixes
fuente
Hay un método en el ejecutor
getActiveCount()
, que proporciona el recuento de subprocesos activos.Después de atravesar el hilo, podemos verificar si el
activeCount()
valor es0
. Una vez que el valor es cero, significa que no hay hilos activos actualmente en ejecución, lo que significa que la tarea ha finalizado:fuente