Preciso executar uma quantidade de tarefas 4 de cada vez, algo como isto:
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
//...wait for completion somehow
Como posso ser notificado quando todos eles estiverem completos? Por enquanto, não consigo pensar em nada melhor do que definir um contador de tarefas global e diminuí-lo no final de cada tarefa; em seguida, monitore em loop infinito esse contador para se tornar 0; ou obtenha uma lista de futuros e no monitor de loop infinito é feito para todos eles. Quais são as melhores soluções que não envolvem loops infinitos?
Obrigado.
Long.MAX_VALUE, TimeUnit.NANOSECONDS
equivalente a não ter um tempo limite.java.util.concurrent
pacote de documentação sob aTiming
seção: Para esperar "para sempre", você pode usar um valor deLong.MAX_VALUE
Use um CountDownLatch :
e dentro da sua tarefa (coloque em try / finalmente)
fonte
ExecutorService.invokeAll()
faz isso por você.fonte
futures
retornados, as tarefas não foram concluídas. Eles podem ser concluídos no futuro e você terá um link para o resultado. É por isso que é chamado deFuture
. Você tem o método Future.get () , que aguardará a conclusão da tarefa para obter um resultado.Você também pode usar Listas de futuros:
então, quando você deseja ingressar em todos eles, é essencialmente o equivalente a ingressar em cada um (com o benefício adicional de que ele gera exceções de threads filho para a principal):
Basicamente, o truque é chamar .get () em cada futuro, um de cada vez, em vez de um loop infinito de chamada isDone () ativada (todas ou cada). Portanto, você está garantido para "seguir em frente" através e além deste bloco assim que o último thread terminar. A ressalva é que, como a chamada .get () gera novamente exceções, se um dos threads morrer, você poderá aumentar isso possivelmente antes que os outros threads tenham sido concluídos [para evitar isso, adicione um https: // stackoverflow.com/a/31885029/32453
catch ExecutionException
chamada get ] A outra ressalva é que ele mantém uma referência a todos os encadeamentos, portanto, se eles tiverem variáveis locais de encadeamento, não serão coletados até depois que você passar por esse bloco (embora você possa contornar isso, se houver algum problema, removendo O futuro está fora do ArrayList). Se você quiser saber qual futuro "termina primeiro"fonte
ExecutorCompletionService.take
: stackoverflow.com/a/11872604/199364No Java8, você pode fazer isso com o CompletableFuture :
fonte
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 } }
Apenas meus dois centavos. Para superar o requisito de
CountDownLatch
conhecer antecipadamente o número de tarefas, você pode fazer da maneira antiga usando um simplesSemaphore
.Na sua tarefa, basta ligar
s.release()
como farialatch.countDown();
fonte
release
chamadas acontecessem antes daacquire
chamada, mas depois de ler a documentação do Semáforo, vejo que está tudo bem.Um pouco tarde para o jogo, mas por uma questão de conclusão ...
Em vez de "esperar" que todas as tarefas terminem, você pode pensar em termos do princípio de Hollywood: "não me ligue, eu te ligo" - quando terminar. Eu acho que o código resultante é mais elegante ...
Goiaba oferece algumas ferramentas interessantes para fazer isso.
Um exemplo ::
Agrupar um ExecutorService em um ListeningExecutorService ::
Envie uma coleção de callables para execução:
Agora a parte essencial:
Anexe um retorno de chamada ao ListenableFuture, que você poderá usar para ser notificado quando todos os futuros forem concluídos:
Isso também oferece a vantagem de que você pode coletar todos os resultados em um único local após o término do processamento ...
Mais informações aqui
fonte
runOnUiThread()
noonSuccess()
.A classe CyclicBarrier no Java 5 e posterior foi projetada para esse tipo de coisa.
fonte
Siga uma das abordagens abaixo.
submit
emExecutorService
e verificar o estado com bloqueio de chamadasget()
emFuture
objeto como sugerido porKiran
invokeAll()
no ExecutorServiceshutdown, awaitTermination, shutdownNow
APIs do ThreadPoolExecutor na sequência apropriadaPerguntas relacionadas ao SE:
Como o CountDownLatch é usado no Multithreading Java?
Como desligar corretamente java ExecutorService
fonte
Aqui estão duas opções, apenas confundam qual é a melhor opção.
Opção 1:
Opção 2:
Aqui colocando future.get (); em tentar pegar é boa ideia né?
fonte
Você pode agrupar suas tarefas em outro executável, que enviará notificações:
fonte
completed
contador. Portanto, depois de iniciar todos eles, a cada notificação, poderá determinar se todas as tarefas foram concluídas. Observe que é vital usá-try/finally
lo para que uma notificação finalizada (ou uma notificação alternativa emcatch
bloco) seja dada mesmo se uma tarefa falhar. Caso contrário, esperaria para sempre.Acabei de escrever um programa de amostra que resolve seu problema. Não houve uma implementação concisa, portanto, adicionarei uma. Embora você possa usar
executor.shutdown()
eexecutor.awaitTermination()
, não é a melhor prática, pois o tempo gasto por diferentes segmentos seria imprevisível.fonte
Só para fornecer mais alternativas aqui diferentes, use trava / barreiras. Você também pode obter os resultados parciais até que todos eles terminem usando CompletionService .
Na Java Concurrency na prática: "Se você tem um lote de cálculos a enviar a um Executor e deseja recuperar os resultados à medida que eles se tornam disponíveis, você pode reter o Futuro associado a cada tarefa e pesquisar repetidamente a conclusão, chamando get com um tempo limite de zero. Isso é possível, mas tedioso . Felizmente, existe uma maneira melhor : um serviço de conclusão ".
Aqui a implementação
fonte
Esta é a minha solução, baseada na dica "AdamSkywalker", e funciona
fonte
Você pode usar este código:
fonte
Eu criei o seguinte exemplo de trabalho. A idéia é ter uma maneira de processar um conjunto de tarefas (estou usando uma fila como exemplo) com muitos Threads (determinados programaticamente pelo número de Tarefas / limite) e aguardar até que todos os Threads sejam concluídos para continuar com outro processamento.
Espero que ajude!
fonte
Você pode usar sua própria subclasse de ExecutorCompletionService para quebrar
taskExecutor
e sua própria implementação do BlockingQueue para ser informado quando cada tarefa for concluída e executar qualquer retorno de chamada ou outra ação que você desejar quando o número de tarefas concluídas atingir o objetivo desejado.fonte
você deve usar
executorService.shutdown()
eexecutorService.awaitTermination
método.Um exemplo da seguinte maneira:
fonte
Então, eu posto minha resposta da pergunta vinculada aqui, caso alguém queira uma maneira mais simples de fazer isso
fonte
Java 8 - Podemos usar a API de fluxo para processar o fluxo. Veja o snippet abaixo
fonte
Se
doSomething()
lançar outras exceções, alatch.countDown()
aparência não será executada, então o que devo fazer?fonte
se você usar mais encadeamentos ExecutionServices SEQUENCIALMENTE e desejar esperar que CADA EXECUTIONSERVICE seja concluído. A melhor maneira é como abaixo;
fonte
Isso pode ajudar
fonte
Você pode chamar waitTillDone () nesta classe Runner :
Você pode reutilizar essa classe e chamar waitTillDone () quantas vezes quiser antes de chamar shutdown (), além de seu código ser extremamente simples . Além disso, você não precisa saber o número de tarefas antecipadamente.
Para usá-lo basta adicionar este gradle / maven
compile 'com.github.matejtymes:javafixes:1.3.1'
dependência ao seu projeto.Mais detalhes podem ser encontrados aqui:
https://github.com/MatejTymes/JavaFixes
fonte
Existe um método no executor
getActiveCount()
- que fornece a contagem de threads ativos.Após estender o segmento, podemos verificar se o
activeCount()
valor é0
. Quando o valor é zero, significa que não há threads ativos em execução no momento, o que significa que a tarefa foi concluída:fonte