Eu tenho um método que retorna um List
dos futuros
List<Future<O>> futures = getFutures();
Agora, quero esperar até que todos os futuros sejam processados com êxito ou que qualquer uma das tarefas cuja saída seja retornada por um futuro gere uma exceção. Mesmo que uma tarefa gere uma exceção, não faz sentido esperar pelos outros futuros.
Uma abordagem simples seria
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;
}
}
}
Mas o problema aqui é se, por exemplo, o quarto futuro lançar uma exceção, esperarei desnecessariamente os 3 primeiros futuros disponíveis.
Como resolver isso? A contagem decrescente trava a ajuda de alguma maneira? Não consigo usar o Future isDone
porque o documento java diz
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
user93796
fonte
fonte
ExecutionService
para cada "lote" de tarefas, enviá-las a ele e, em seguida, desligar imediatamente o serviço e usáawaitTermination()
-lo, suponho.CountDownLatch
se você envolveu o corpo de todos os seus futuros em umtry..finally
para garantir que a trava também diminua.Respostas:
Você pode usar um CompletionService para receber os futuros assim que estiverem prontos e, se um deles lançar uma exceção, cancele o processamento. Algo assim:
Eu acho que você pode melhorar ainda mais para cancelar as tarefas ainda em execução, se uma delas gerar um erro.
fonte
CompletionService
.Se você estiver usando o Java 8 , poderá fazer isso mais facilmente com CompletableFuture e CompletableFuture.allOf , que aplica o retorno de chamada somente depois que todas as CompletableFutures fornecidas forem concluídas.
fonte
Future
instâncias, não poderá aplicar esse método. Não é fácil converterFuture
emCompletableFuture
.Use a
CompletableFuture
em Java 8fonte
Você pode usar um ExecutorCompletionService . A documentação ainda tem um exemplo para o seu caso de uso exato:
O importante a ser observado aqui é que ecs.take () obterá a primeira tarefa concluída , não apenas a primeira enviada. Portanto, você deve obtê-los na ordem de concluir a execução (ou lançar uma exceção).
fonte
Se você estiver usando o Java 8 e não quiser manipular
CompletableFuture
s, escrevi uma ferramenta para recuperar resultados para umList<Future<T>>
streaming em uso. A chave é que você está proibidomap(Future::get)
enquanto joga.Isso precisa de um
AggregateException
que funcione como o C #Esse componente atua exatamente como Task.WaitAll do C # . Estou trabalhando em uma variante que faz o mesmo que
CompletableFuture.allOf
(equivalente aTask.WhenAll
)A razão pela qual fiz isso é que estou usando o Spring
ListenableFuture
e não quero portar,CompletableFuture
apesar de ser uma maneira mais padrãofonte
Caso deseje combinar uma Lista de CompletableFutures, você pode fazer isso:
Para obter mais detalhes sobre o Future & CompletableFuture, links úteis:
1. Futuro: https://www.baeldung.com/java-future
2. CompletableFuture: https://www.baeldung.com/java-completablefuture
3. CompletableFuture: https : //www.callicoder.com/java-8-completablefuture-tutorial/
fonte
Talvez isso ajude (nada seria substituído pelo thread bruto, sim!). Sugiro que execute cada
Future
indivíduo com um thread separado (eles ficam paralelos); então, sempre que um dos erros ocorrer , basta sinalizar para o gerente (Handler
classe).Devo dizer que o código acima apresentaria um erro (não foi verificado), mas espero poder explicar a solução. por favor, tente.
fonte
fonte
O CompletionService utilizará seus Callables com o método .submit () e você poderá recuperar os futuros calculados com o método .take ().
Uma coisa que você não deve esquecer é encerrar o ExecutorService chamando o método .shutdown (). Além disso, você só pode chamar esse método quando tiver salvo uma referência ao serviço do executor, portanto, mantenha-o.
Código de exemplo - Para um número fixo de itens de trabalho a serem trabalhados em paralelo:
Código de exemplo - Para um número dinâmico de itens de trabalho a serem trabalhados em paralelo:
fonte
Eu tenho uma classe de utilitário que contém estes:
Depois disso, usando uma importação estática, você pode simplesmente esperar por todos os futuros como este:
você também pode coletar todos os resultados assim:
Apenas revisitando meu post antigo e percebendo que você teve outra tristeza:
Nesse caso, a solução simples é fazer isso em paralelo:
Dessa forma, a primeira exceção, embora não pare o futuro, interromperá a instrução forEach, como no exemplo de série, mas como todos esperam em paralelo, não será necessário aguardar a conclusão dos três primeiros.
fonte
fonte