Disons que j'ai une file d'attente pleine de tâches que je dois soumettre à un service d'exécuteur testamentaire. Je veux qu'ils soient traités un à la fois. Le moyen le plus simple auquel je puisse penser est de:
- Prendre une tâche de la file d'attente
- Soumettez-le à l'exécuteur testamentaire
- Appelez .get sur le Future retourné et bloquez jusqu'à ce qu'un résultat soit disponible
- Prenez une autre tâche de la file d'attente ...
Cependant, j'essaie d'éviter de bloquer complètement. Si j'ai 10000 de ces files d'attente, qui nécessitent que leurs tâches soient traitées une par une, je vais manquer d'espace dans la pile, car la plupart d'entre elles conserveront les threads bloqués.
Ce que je voudrais, c'est soumettre une tâche et fournir un rappel qui est appelé lorsque la tâche est terminée. J'utiliserai cette notification de rappel comme indicateur pour envoyer la tâche suivante. (Functionaljava et Jetlang utilisent apparemment de tels algorithmes non bloquants, mais je ne comprends pas leur code)
Comment puis-je faire cela en utilisant java.util.concurrent de JDK, sans écrire mon propre service exécuteur?
(la file d'attente qui me nourrit de ces tâches peut elle-même se bloquer, mais c'est un problème à résoudre plus tard)
Callback
interface que vous déclarez; pas d'une bibliothèque. De nos jours, j'utiliserais probablement justeRunnable
,Consumer
ouBiConsumer
, selon ce que je dois passer en arrière de la tâche à l'auditeur.Dans Java 8, vous pouvez utiliser CompletableFuture . Voici un exemple que j'ai eu dans mon code où je l'utilise pour récupérer les utilisateurs de mon service utilisateur, les mapper à mes objets de vue, puis mettre à jour ma vue ou afficher une boîte de dialogue d'erreur (il s'agit d'une application GUI):
Il s'exécute de manière asynchrone. J'utilise deux méthodes privées:
mapUsersToUserViews
etupdateView
.la source
Utilisez la future API écoutable de Guava et ajoutez un rappel. Cf. depuis le site Web:
la source
Vous pouvez étendre la
FutureTask
classe et redéfinir ladone()
méthode, puis ajouter l'FutureTask
objet auExecutorService
, de sorte que ladone()
méthode s'appellera une fois l'opérationFutureTask
terminée immédiatement.la source
then add the FutureTask object to the ExecutorService
, pourriez-vous s'il vous plaît me dire comment faire cela?ThreadPoolExecutor
a égalementbeforeExecute
et desafterExecute
méthodes hook que vous pouvez remplacer et utiliser. Voici la descriptionThreadPoolExecutor
des Javadocs de .la source
Utilisez un
CountDownLatch
.C'est de
java.util.concurrent
et c'est exactement la façon d'attendre que plusieurs threads se terminent l'exécution avant de continuer.Afin d'obtenir l'effet de rappel que vous recherchez, cela nécessite un peu de travail supplémentaire. À savoir, le gérer vous-même dans un thread séparé qui utilise le
CountDownLatch
et l'attend, puis continue à notifier ce que vous devez notifier. Il n'y a pas de support natif pour le rappel, ou quelque chose de similaire à cet effet.EDIT: maintenant que je comprends mieux votre question, je pense que vous allez trop loin, inutilement. Si vous prenez un régulier
SingleThreadExecutor
, donnez-lui toutes les tâches, et il fera la file d'attente de manière native.la source
Si vous souhaitez vous assurer qu'aucune tâche ne s'exécutera en même temps, utilisez un SingleThreadedExecutor . Les tâches seront traitées dans l'ordre où elles sont soumises. Vous n'avez même pas besoin de tenir les tâches, soumettez-les simplement à l'exécutif.
la source
Code simple pour implémenter le
Callback
mécanisme en utilisantExecutorService
production:
Notes clés:
newFixedThreadPool(5)
parnewFixedThreadPool(1)
Si vous souhaitez traiter la tâche suivante après avoir analysé le résultat
callback
de la tâche précédente, annulez simplement le commentaire sous la ligneVous pouvez remplacer
newFixedThreadPool()
par l'un desen fonction de votre cas d'utilisation.
Si vous souhaitez gérer la méthode de rappel de manière asynchrone
une. Passer une
ExecutorService or ThreadPoolExecutor
tâche partagée à appelableb. Convertissez votre
Callable
méthode enCallable/Runnable
tâchec. Pousser la tâche de rappel vers
ExecutorService or ThreadPoolExecutor
la source
Juste pour ajouter à la réponse de Matt, qui a aidé, voici un exemple plus étoffé pour montrer l'utilisation d'un rappel.
La sortie est:
la source
Vous pouvez utiliser une implémentation de Callable telle que
où CallbackInterface est quelque chose de très basique comme
et maintenant la classe principale ressemblera à ceci
la source
Ceci est une extension de la réponse de Pache utilisant celle de Guava
ListenableFuture
.En particulier, les
Futures.transform()
retoursListenableFuture
ainsi peuvent être utilisés pour enchaîner les appels asynchrones.Futures.addCallback()
renvoievoid
, donc ne peut pas être utilisé pour le chaînage, mais est bon pour gérer le succès / échec lors d'un achèvement asynchrone.REMARQUE: Outre le chaînage des tâches asynchrones,
Futures.transform()
vous permet également de planifier chaque tâche sur un exécuteur distinct (non illustré dans cet exemple).la source