J'ai quelques tâches asynchrones en cours d'exécution et j'ai besoin d'attendre qu'au moins l'une d'entre elles soit terminée (à l'avenir, probablement j'aurai besoin d'attendre que M sur N tâches soient terminées). Actuellement, elles sont présentées sous forme de Future, donc j'ai besoin de quelque chose comme
/**
* Bloque le thread actuel jusqu'à ce qu'un des futurs spécifiés soit terminé et le renvoie.
*/
public static Future waitForAny(Collection> futures)
throws AllFuturesFailedException
Est-ce qu'il y a quelque chose de similaire à cela? Ou quelque chose de similaire, pas nécessairement pour Future. Actuellement, je boucle à travers la collection de futurs, vérifie si l'un est terminé, puis attends pendant un certain temps et vérifie à nouveau. Cela ne semble pas être la meilleure solution, car si j'attends pendant une longue période, alors un retard non souhaité est ajouté, si j'attends pendant une courte période, cela peut affecter les performances.
Je pourrais essayer d'utiliser
new CountDownLatch(1)
et diminuer le décompte lorsque la tâche est terminée et faire
countdown.await()
, mais j'ai découvert qu'il est possible seulement si je contrôle la création du Future. C'est possible, mais cela nécessite une refonte du système, car actuellement la logique de création des tâches (envoi de Callable à ExecutorService) est séparée de la décision d'attendre pour quel Future. Je pourrais également remplacer
RunnableFuture AbstractExecutorService.newTaskFor(Callable callable)
et créer une implémentation personnalisée de RunnableFuture avec la capacité de rattacher un auditeur pour être notifié lorsque la tâche est terminée, puis attacher un tel auditeur aux tâches nécessaires et utiliser CountDownLatch, mais cela signifie que je dois remplacer newTaskFor pour chaque ExecutorService que j'utilise - et potentiellement il y aura des implémentations qui n'étendent pas AbstractExecutorService. Je pourrais également essayer de décorer le ExecutorService donné à cette fin, mais alors je dois décorer toutes les méthodes produisant des Futures.
Toutes ces solutions peuvent fonctionner mais semblent très artificielles. On dirait que je rate quelque chose de simple, comme
WaitHandle.WaitAny(WaitHandle[] waitHandles)
en c#. Y a-t-il des solutions bien connues pour ce genre de problème?
MISE À JOUR:
À l'origine, je n'avais pas du tout accès à la création de Futures, donc il n'y avait pas de solution élégante. Après avoir redessiné le système, j'ai eu accès à la création de Futures et j'ai pu ajouter countDownLatch.countdown() au processus d'exécution, puis je peux countDownLatch.await() et tout fonctionne bien. Merci pour les autres réponses, je ne connaissais pas ExecutorCompletionService et cela peut effectivement être utile dans des tâches similaires, mais dans ce cas particulier, il ne pouvait pas être utilisé car certains Futures sont créés sans aucun exécuteur - la tâche réelle est envoyée à un autre serveur via le réseau, se termine à distance et la notification de terminaison est reçue.
4 votes
Beaucoup de personnes qui viennent à cette question préféreront probablement regarder en dessous de la réponse longuement acceptée aux réponses les mieux votées qui se réfèrent à
ExecutorCompletionService
etExecutorService.invokeAny()
.