У меня работает несколько асинхронных задач, и мне нужно подождать, пока хотя бы одна из них будет завершена (в будущем, вероятно, мне придется подождать, пока утилита M из N будет завершена).
В настоящее время они представлены как Future, поэтому мне нужно что-то вроде
/**
* 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)
в c #. Есть ли известные решения для такого рода проблем?
UPDATE:
Изначально у меня вообще не было доступа к созданию будущего, поэтому не было элегантного решения. После редизайна системы я получил доступ к созданию Future и смог добавить countDownLatch.countdown () в процесс выполнения, затем я могу считать countDownLatch.await (), и все работает отлично.
Спасибо за другие ответы, я не знал о ExecutorCompletionService, и он действительно может быть полезен в подобных задачах, но в данном конкретном случае его нельзя использовать, потому что некоторые Futures создаются без какого-либо исполнителя - фактическая задача отправляется на другой сервер через сеть, завершается удаленно и уведомление о завершении получено.