¿Cuál es la forma más sencilla de esperar ExecutorServicea que finalicen todas las tareas ? Mi tarea es principalmente computacional, por lo que solo quiero ejecutar una gran cantidad de trabajos, uno en cada núcleo. En este momento mi configuración se ve así:
ExecutorService es = Executors.newFixedThreadPool(2);
for (DataTable singleTable : uniquePhrases) {
es.execute(new ComputeDTask(singleTable));
}
try{
es.wait();
}
catch (InterruptedException e){
e.printStackTrace();
}
ComputeDTaskImplementos ejecutables. Esto aparece para ejecutar las tareas correctamente, pero el código se bloquea en wait()la IllegalMonitorStateException. Esto es extraño, porque jugué con algunos ejemplos de juguetes y parecía funcionar.
uniquePhrasescontiene varias decenas de miles de elementos. ¿Debo estar usando otro método? Estoy buscando algo lo mas simple posible
java
multithreading
threadpool
executorservice
george smiley
fuente
fuente

es) cuando desea esperarlo; el bloqueo se liberará automáticamente mientras esperaExecutors.newFixedThreadPool(System.getRuntime().availableProcessors());Respuestas:
El enfoque más simple es usar el
ExecutorService.invokeAll()que hace lo que quieres en una sola línea. En su lenguaje, necesitará modificar o ajustarComputeDTaskpara implementarCallable<>, lo que puede brindarle un poco más de flexibilidad. Probablemente en su aplicación hay una implementación significativa deCallable.call(), pero aquí hay una manera de envolverla si no la está usandoExecutors.callable().Como otros han señalado, puede usar la versión de tiempo de espera de,
invokeAll()si corresponde. En este ejemplo,answersva a contener un montón deFutures que devolverán valores nulos (consulte la definición deExecutors.callable(). Probablemente lo que quiera hacer es una ligera refactorización para que pueda obtener una respuesta útil o una referencia al subyacenteComputeDTask, pero puedo No cuentes con tu ejemplo.Si no está claro, tenga en cuenta que
invokeAll()no volverá hasta que se completen todas las tareas. (es decir, todos los mensajes de correo electrónico deFuturesuanswerscolección informarán.isDone()si se le solicita). Esto evita todo el apagado manual, esperar la terminación, etc. y le permite volver a usarloExecutorServiceordenadamente durante varios ciclos, si lo desea.Hay algunas preguntas relacionadas sobre SO:
Cómo esperar a que todos los hilos terminen
Valores de retorno de hilos Java
invokeAll () no está dispuesto a aceptar una Colección <invocable <t>>
¿Necesito sincronizar?
Ninguno de estos es estrictamente adecuado para su pregunta, pero proporcionan un poco de color sobre cómo la gente piensa
Executor/ExecutorServicedebe ser utilizado.fuente
Si desea esperar a que se completen todas las tareas, use el
shutdownmétodo en lugar dewait. Luego sígalo conawaitTermination.Además, puede usar
Runtime.availableProcessorspara obtener el número de subprocesos de hardware para que pueda inicializar su conjunto de subprocesos correctamente.fuente
awaitTerminationrequiere tiempo de espera como parámetro. Si bien es posible proporcionar un tiempo finito y colocar un bucle a su alrededor para esperar hasta que todos los hilos hayan terminado, me preguntaba si había una solución más elegante.Si esperar
ExecutorServicea que finalicen todas las tareas no es precisamente su objetivo, sino esperar hasta que se haya completado un lote específico de tareas , puede utilizar unCompletionService- específicamente, unExecutorCompletionService.La idea es crear una
ExecutorCompletionServiceenvolturaExecutor, enviar una cantidad conocida de tareas a través deCompletionService, y luego extraer esa misma cantidad de resultados de la cola de finalización utilizandotake()(qué bloques) opoll()(qué no). Una vez que haya dibujado todos los resultados esperados correspondientes a las tareas que envió, sabrá que todos están listos.Permítanme decir esto una vez más, porque no es obvio desde la interfaz: debe saber cuántas cosas pone en el
CompletionServicepara poder saber cuántas cosas tratar de extraer. Esto importa especialmente con eltake()método: llámelo una vez más y bloqueará su hilo de llamada hasta que otro hilo envíe otro trabajo al mismoCompletionService.Hay algunos ejemplos que muestran cómo usar
CompletionServiceen el libro Java Concurrency in Practice .fuente
CompletionServiceSi desea esperar a que el servicio del ejecutor termine de ejecutarse, llame
shutdown()y luego, espere Terminación (unidades, tipo de unidad) , por ejemploawaitTermination(1, MINUTE). El ExecutorService no bloquea en su propio monitor, por lo que no puede usar,waitetc.fuente
awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);Podría esperar a que finalicen los trabajos en un intervalo determinado:
O puede usar ExecutorService . submit ( Runnable ) y recoge los objetos Future que devuelve y llama a get () en cada turno para esperar a que finalicen.
InterruptedException es extremadamente importante para manejar adecuadamente. Es lo que le permite a usted o a los usuarios de su biblioteca finalizar un proceso largo de forma segura.
fuente
Solo usa
En cada hilo
y como barrera
fuente
Causa raíz de IllegalMonitorStateException :
Desde su código, acaba de llamar a wait () en ExecutorService sin poseer el bloqueo.
Debajo del código arreglará
IllegalMonitorStateExceptionSiga uno de los siguientes enfoques para esperar la finalización de todas las tareas que se han enviado
ExecutorService.Itere a través de todas las
Futuretareas desdesubmitencendidoExecutorServicey verifique el estado bloqueando la llamadaget()en elFutureobjetoUsando invokeAll en
ExecutorServiceUsando CountDownLatch
Usando ForkJoinPool o newWorkStealingPool de
Executors(desde java 8)Cierre el grupo como se recomienda en la página de documentación de Oracle
Si desea esperar con gracia la finalización de todas las tareas cuando utiliza la opción 5 en lugar de las opciones 1 a 4, cambie
a
un
while(condition)que verifica cada 1 minuto.fuente
Puede usar el
ExecutorService.invokeAllmétodo, ejecutará todas las tareas y esperará hasta que todos los hilos terminen su tarea.Aquí está completo javadoc
También puede usar una versión sobrecargada de este método para especificar el tiempo de espera.
Aquí hay un código de muestra con
ExecutorService.invokeAllfuente
También tengo la situación de que tengo que rastrear un conjunto de documentos. Comienzo con un documento inicial "inicial" que debe procesarse, ese documento contiene enlaces a otros documentos que también deben procesarse, y así sucesivamente.
En mi programa principal, solo quiero escribir algo como lo siguiente, donde
Crawlercontrola un montón de hilos.La misma situación sucedería si quisiera navegar por un árbol; aparecería en el nodo raíz, el procesador para cada nodo agregaría hijos a la cola según sea necesario, y un grupo de subprocesos procesaría todos los nodos en el árbol, hasta que no hubiera más.
No pude encontrar nada en la JVM que me pareció un poco sorprendente. Así que escribí una clase
ThreadPoolque se puede usar directamente o subclase para agregar métodos adecuados para el dominio, por ejemploschedule(Document). ¡Espero eso ayude!ThreadPool Javadoc | Maven
fuente
Agregue todos los hilos en la colección y envíelo usando
invokeAll. Si puede usar elinvokeAllmétodo deExecutorService, JVM no procederá a la siguiente línea hasta que todos los hilos estén completos.Aquí hay un buen ejemplo: invokeAll a través de ExecutorService
fuente
Envíe sus tareas al Runner y luego espere llamando al método waitTillDone () de esta manera:
Para usarlo agregue esta dependencia gradle / maven:
'com.github.matejtymes:javafixes:1.0'Para obtener más detalles, consulte aquí: https://github.com/MatejTymes/JavaFixes o aquí: http://matejtymes.blogspot.com/2016/04/executor-that-notifies-you-when-task.html
fuente
Una alternativa simple a esto es usar hilos junto con join. Consulte: Unir hilos
fuente
Solo esperaré a que el ejecutor termine con un tiempo de espera especificado que crees que es adecuado para completar las tareas.
fuente
Suena como lo que necesita
ForkJoinPooly utiliza el grupo global para ejecutar tareas.La belleza está en
pool.awaitQuiescencedonde el método bloqueará, utilice el hilo de la persona que llama para ejecutar sus tareas y luego regrese cuando esté realmente vacío.fuente