У меня запущено несколько асинхронных задач, и мне нужно подождать, пока, по крайней мере, один из них не будет завершен (в будущем, вероятно, мне нужно будет подождать, чтобы утилита M из N задач была завершена). В настоящее время они представлены как Будущее, поэтому мне нужно что-то вроде
/**
* Blocks current thread until one of specified futures is done and returns it.
*/
public static <T> Future<T> waitForAny(Collection<Future<T>> futures)
throws AllFuturesFailedException
Есть ли что-нибудь подобное? Или что-то подобное, не нужно для будущего. В настоящее время я просматриваю сборник фьючерсов, проверяю, завершен ли он, затем некоторое время спят и снова проверяем. Это выглядит не лучшим решением, потому что если я сплю в течение длительного времени, то добавляется нежелательная задержка, если я сплю в течение короткого периода времени, это может повлиять на производительность.
Я мог бы попробовать использовать
new CountDownLatch(1)
и уменьшите обратный отсчет при завершении задачи и выполните
countdown.await()
но я нашел это возможным, только если я буду управлять будущим. Это возможно, но требует редизайна системы, поскольку в настоящее время логика создания задач (отправка Callable в ExecutorService) отделена от решения ждать, какое будущее. Я мог бы также переопределить
<T> RunnableFuture<T> AbstractExecutorService.newTaskFor(Callable<T> callable)
и создать пользовательскую реализацию RunnableFuture с возможностью прикреплять слушателя к уведомлению о завершении задачи, затем присоединить такой прослушиватель к нужным задачам и использовать CountDownLatch, но это означает, что я должен переопределить newTaskFor для каждого используемого мной ExecutorService - и, возможно, там будут реализованы, которые не распространяются на AbstractExecutorService. Я мог бы также попробовать обернуть данный ExecutorService с той же целью, но тогда я должен украсить все методы, производящие Futures.
Все эти решения могут работать, но кажутся очень неестественными. Похоже, я пропустил что-то простое, например
WaitHandle.WaitAny(WaitHandle[] waitHandles)
в С#. Существуют ли хорошо известные решения для такого рода задач?
UPDATE:
Изначально у меня не было доступа к созданию Future вообще, поэтому не было элегантного решения. После перепроектирования системы я получил доступ к созданию Future и смог добавить countDownLatch.countdown() в процесс выполнения, затем я могу countDownLatch.await(), и все работает нормально. Спасибо за другие ответы, я не знал об ExecutorCompletionService, и он действительно может быть полезен в подобных задачах, но в этом конкретном случае он не может быть использован, поскольку некоторые фьючерсы создаются без какого-либо исполнителя - фактическая задача отправляется на другой сервер через сеть, завершается удаленно и получено уведомление о завершении.