Qual é a maneira mais simples de aguardar o ExecutorService
término de todas as tarefas ? Minha tarefa é principalmente computacional, então eu só quero executar um grande número de tarefas - uma em cada núcleo. No momento, minha configuração fica assim:
ExecutorService es = Executors.newFixedThreadPool(2);
for (DataTable singleTable : uniquePhrases) {
es.execute(new ComputeDTask(singleTable));
}
try{
es.wait();
}
catch (InterruptedException e){
e.printStackTrace();
}
ComputeDTask
implementa executável. Isso parece executar as tarefas corretamente, mas o código falha wait()
com IllegalMonitorStateException
. Isso é estranho, porque eu brinquei com alguns exemplos de brinquedos e pareceu funcionar.
uniquePhrases
contém várias dezenas de milhares de elementos. Devo estar usando outro método? Estou procurando algo o mais simples possível
java
multithreading
threadpool
executorservice
sorriso de george
fonte
fonte
es
) quando quiser esperar - o bloqueio será liberado automaticamente enquanto a esperaExecutors.newFixedThreadPool(System.getRuntime().availableProcessors());
Respostas:
A abordagem mais simples é usar
ExecutorService.invokeAll()
o que você deseja em uma única linha. Na sua linguagem, você precisará modificar ou agruparComputeDTask
para implementarCallable<>
, o que pode lhe dar um pouco mais de flexibilidade. Provavelmente em seu aplicativo há uma implementação significativa deCallable.call()
, mas aqui está uma maneira de envolvê-lo, se não estiver usandoExecutors.callable()
.Como outros já apontaram, você pode usar a versão de tempo limite,
invokeAll()
se apropriado. Neste exemplo,answers
irá conter um monte deFuture
s que retornará nulos (consulte a definição deExecutors.callable()
. Provavelmente o que você deseja fazer é uma leve refatoração para que você possa obter uma resposta útil de volta ou uma referência ao subjacenteComputeDTask
, mas eu posso conte do seu exemplo.Se não estiver claro, observe que
invokeAll()
não retornará até que todas as tarefas sejam concluídas. (ou seja, todos osFuture
s da suaanswers
coleção reportarão.isDone()
se solicitado.) Isso evita todo o desligamento manual, aguarda o término, etc ... e permite reutilizá-loExecutorService
ordenadamente por vários ciclos, se desejado.Existem algumas perguntas relacionadas ao SO:
Como aguardar a conclusão de todos os threads
Retornar valores dos encadeamentos java
invokeAll () não está disposto a aceitar uma coleção <Callable <t>>
Preciso sincronizar?
Nada disso é estritamente correto para sua pergunta, mas eles fornecem um pouco de cor sobre como as pessoas pensam
Executor
/ExecutorService
devem ser usadas.fonte
Se você deseja aguardar a conclusão de todas as tarefas, use o
shutdown
método em vez dewait
. Então siga comawaitTermination
.Além disso, você pode usar
Runtime.availableProcessors
para obter o número de threads de hardware para inicializar seu pool de threads corretamente.fonte
awaitTermination
requer tempo limite como parâmetro. Embora seja possível fornecer um tempo finito e colocar um loop em torno dele para esperar até que todos os threads terminem, eu queria saber se havia uma solução mais elegante.Se aguardar
ExecutorService
a conclusão de todas as tarefas não for exatamente o seu objetivo, mas aguardar até que um lote específico de tarefas seja concluído, você poderá usar umCompletionService
- especificamente, umExecutorCompletionService
.A idéia é criar um
ExecutorCompletionService
empacotamentoExecutor
, enviar um número conhecido de tarefas através do eCompletionService
, em seguida, desenhar o mesmo número de resultados da fila de conclusão usandotake()
(quais blocos) oupoll()
(quais não). Depois de desenhar todos os resultados esperados correspondentes às tarefas enviadas, você sabe que todas elas foram concluídas.Deixe-me declarar isso mais uma vez, porque não é óbvio a partir da interface: você deve saber quantas coisas você colocou
CompletionService
para saber quantas coisas tentar extrair. Isso é importante principalmente com otake()
método: chame-o muitas vezes e ele bloqueará seu thread de chamada até que outro thread envie outro trabalho para o mesmoCompletionService
.Existem alguns exemplos que mostram como usar
CompletionService
no livro Java Concurrency in Practice .fonte
CompletionService
Se você deseja esperar o serviço executor terminar a execução, chame
shutdown()
e aguardeTermination (units, unitType) , por exemploawaitTermination(1, MINUTE)
. O ExecutorService não bloqueia em seu próprio monitor, portanto você não pode usarwait
etc.fonte
awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
stackoverflow.com/a/1250655/32453Você pode esperar a conclusão dos trabalhos em um determinado intervalo:
Ou você pode usar o ExecutorService . envie ( Runnable ) e colete os objetos Future que ele retorna e chame get () em cada um deles para aguardar o término.
InterruptedException é extremamente importante para lidar adequadamente. É o que permite que você ou os usuários da sua biblioteca encerrem um longo processo com segurança.
fonte
Apenas use
Em cada thread
e como barreira
fonte
Causa raiz de IllegalMonitorStateException :
No seu código, você acabou de chamar wait () no ExecutorService sem possuir o bloqueio.
O código abaixo será corrigido
IllegalMonitorStateException
Siga uma das abordagens abaixo para aguardar a conclusão de todas as tarefas submetidas
ExecutorService
.Repita todas as
Future
tarefas a partirsubmit
deExecutorService
e verifique o status com o bloqueio de chamadasget()
noFuture
objetoUsando invokeAll on
ExecutorService
Usando CountDownLatch
Usando ForkJoinPool ou newWorkStealingPool de
Executors
(desde java 8)Encerre o pool conforme recomendado na página de documentação da Oracle
Se você desejar esperar por todas as tarefas para conclusão quando estiver usando a opção 5 em vez das opções 1 a 4, altere
para
um
while(condition)
que verifica a cada 1 minuto.fonte
Você pode usar o
ExecutorService.invokeAll
método, ele executará todas as tarefas e esperará até que todos os threads concluam sua tarefa.Aqui está o javadoc completo
Você também pode usar a versão sobrecarregada desse método para especificar o tempo limite.
Aqui está um código de exemplo com
ExecutorService.invokeAll
fonte
Também tenho a situação de ter um conjunto de documentos a serem rastreados. Começo com um documento inicial "inicial" que deve ser processado, que contém links para outros documentos que também devem ser processados e assim por diante.
No meu programa principal, eu só quero escrever algo como o seguinte, onde
Crawler
controla um monte de threads.A mesma situação aconteceria se eu quisesse navegar em uma árvore; eu apareceria no nó raiz, o processador de cada nó adicionaria filhos à fila, conforme necessário, e um monte de threads processaria todos os nós na árvore, até que não houvesse mais.
Não consegui encontrar nada na JVM que achei um pouco surpreendente. Então, eu escrevi uma classe
ThreadPool
que pode ser usada diretamente ou subclasse para adicionar métodos adequados para o domínio, por exemploschedule(Document)
. Espero que ajude!ThreadPool Javadoc | Maven
fonte
Adicione todos os tópicos da coleção e envie-os usando
invokeAll
. Se você puder usar oinvokeAll
método ofExecutorService
, a JVM não continuará para a próxima linha até que todos os encadeamentos sejam concluídos.Aqui está um bom exemplo: invokeAll via ExecutorService
fonte
Envie suas tarefas para o Runner e aguarde chamando o método waitTillDone () assim:
Para usá-lo, adicione esta dependência gradle / maven:
'com.github.matejtymes:javafixes:1.0'
Para obter mais detalhes, consulte aqui: https://github.com/MatejTymes/JavaFixes ou aqui: http://matejtymes.blogspot.com/2016/04/executor-that-notifies-you-when-task.html
fonte
Uma alternativa simples para isso é usar threads junto com join. Consulte: Juntando tópicos
fonte
Vou aguardar que o executor termine com um tempo limite especificado que você acha que é adequado para a conclusão das tarefas.
fonte
Parece que você precisa
ForkJoinPool
e usa o pool global para executar tarefas.A beleza é
pool.awaitQuiescence
onde o método bloqueará utilizar o encadeamento do chamador para executar suas tarefas e retornar quando estiver realmente vazio.fonte