Poczekaj, aż skończy się którykolwiek z elementów Future <T>

Mam kilka uruchomionych zadań asynchronicznych i muszę poczekać, aż przynajmniej jeden z nich zostanie zakończony (w przyszłości prawdopodobnie będę musiał poczekać, aż skończy się M z N zadań). Obecnie są przedstawiane jako Future, więc potrzebuję czegoś takiego

/**
 * 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

Czy jest coś takiego? Albo coś podobnego, nie koniecznego dla przyszłości. Obecnie przeglądam kolekcję kontraktów terminowych, sprawdzam, czy jest zakończona, a następnie śpię przez jakiś czas i sprawdzam ponownie. Nie wygląda to na najlepsze rozwiązanie, ponieważ jeśli śpię przez dłuższy czas, to dodawane jest niechciane opóźnienie, a jeśli śpię przez krótki czas, może to wpłynąć na wydajność.

Mogę spróbować użyć

new CountDownLatch(1)

i zmniejsz odliczanie, gdy zadanie jest zakończone i wykonaj

countdown.await()

, ale znalazłem to możliwe tylko wtedy, gdy kontroluję tworzenie Przyszłości. Jest to możliwe, ale wymaga przeprojektowania systemu, ponieważ obecnie logika tworzenia zadań (wysyłanie Callable do ExecutorService) jest oddzielona od decyzji o oczekiwaniu na którą Future. Mogłem także zastąpić

<T> RunnableFuture<T> AbstractExecutorService.newTaskFor(Callable<T> callable)

i stwórz niestandardową implementację RunnableFuture z możliwością dołączenia nasłuchiwania w celu powiadomienia, gdy zadanie zostanie zakończone, a następnie dołącz taki listener do potrzebnych zadań i użyj CountDownLatch, ale to oznacza, że ​​muszę przesłonić newTaskFor dla każdej używanej usługi ExecutorService - i potencjalnie będzie implementacja które nie rozszerzają usługi AbstractExecutorService. Mógłbym również spróbować zawijać dany ExecutorService w tym samym celu, ale potem muszę udekorować wszystkie metody produkcji Futures.

Wszystkie te rozwiązania mogą działać, ale wydają się bardzo nienaturalne. Wygląda na to, że tęsknię za czymś prostym

WaitHandle.WaitAny(WaitHandle[] waitHandles)

w c #. Czy są jakieś znane rozwiązania tego rodzaju problemów?

AKTUALIZACJA:

Pierwotnie nie miałem dostępu do tworzenia Przyszłości, więc nie było eleganckiego rozwiązania. Po przeprojektowaniu systemu uzyskałem dostęp do tworzenia Future i mogłem dodać countDownLatch.countdown () do procesu wykonywania, a następnie mogę countDownLatch.await () i wszystko działa dobrze. Dziękuję za inne odpowiedzi, nie wiedziałem o ExecutorCompletionService i rzeczywiście może być pomocny w podobnych zadaniach, ale w tym konkretnym przypadku nie można go użyć, ponieważ niektóre Futures są tworzone bez żadnego executora - rzeczywiste zadanie jest wysyłane na inny serwer za pośrednictwem sieci, wykonuje zdalnie i otrzymywane jest powiadomienie o zakończeniu.

questionAnswers(7)

yourAnswerToTheQuestion