Emballage d’une série d’appels asynchrones avec une méthode synchrone avec une valeur de retour

Mon code actuel utilise une série de processus asynchrones qui aboutissent à des résultats. Je dois envelopper chacun de ceux-ci de manière à ce que chacun soit accessible par une méthode synchrone avec le résultat comme valeur de retour. Pour ce faire, je souhaite utiliser les services de l’exécuteur afin de permettre à plusieurs d’entre eux de se produire en même temps. J’ai l’impression que Future pourrait être pertinent pour ma mise en œuvre, mais je ne peux pas trouver un moyen efficace d’y parvenir.

Ce que j’ai maintenant:

public class DoAJob { ResultObject result; public void stepOne() { // Passes self in for a callback otherComponent.doStepOne(this); } // Called back by otherComponent once it has completed doStepOne public void stepTwo(IntermediateData d) { otherComponent.doStepTwo(this, d); } // Called back by otherComponent once it has completed doStepTwo public void stepThree(ResultObject resultFromOtherComponent) { result = resultFromOtherComponent; //Done with process } } 

Cela a très bien fonctionné en interne, mais je dois maintenant mapper mon processus dans une méthode synchrone avec une valeur de retour telle que:

 public ResultObject getResult(){ // ??? What goes here ??? } 

Quelqu’un a-t-il une bonne idée de la manière de mettre en œuvre cela avec élégance?

Si vous souhaitez transformer une opération asynchrone (qui exécute un rappel une fois terminé) en une opération synchrone / bloquante, vous pouvez utiliser une queue de blocage. Vous pouvez envelopper cela dans un object Future si vous le souhaitez.

  1. Définissez une queue bloquante pouvant contenir un seul élément:

    BlockingQueue blockingQueue = new ArrayBlockingQueue(1);

  2. Démarrez votre processus asynchrone (exécuté en arrière-plan) et écrivez le rappel de manière à ce que, le cas échéant, il ajoute son résultat à la queue de blocage.

  3. Dans votre thread d’avant-plan / d’application, indiquez-le () dans la queue jusqu’à ce qu’un élément devienne disponible:

    Result result = blockingQueue.take();

J’ai déjà écrit quelque chose de similaire (le premier plan doit bloquer pour une réponse asynchrone d’une machine distante) en utilisant quelque chose comme un futur, vous pouvez trouver un exemple de code ici .

J’ai fait quelque chose de similaire avec la bibliothèque Guava; ces liens peuvent vous orienter dans la bonne direction:

Est-il possible de chaîner des appels asynchrones à l’aide de Guava?

https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained

Si vous aimez vous salir les mains, vous pouvez le faire

 ResultObject result; public void stepOne() otherComponent.doStepOne(this); synchronized(this) while(result==null) this.wait(); return result; public void stepThree(ResultObject resultFromOtherComponent) result = resultFromOtherComponent; synchronized(this) this.notify(); 

Ou vous pouvez utiliser des outils d’access simultané de niveau supérieur, tels que BlockingQueue, Semaphore, CountdownLatch, Phaser, etc.

Notez que DoAJob n’est pas thread-safe – le problème est assuré si deux threads appellent stepOne en même temps.

Je recommande d’utiliser invokeAll (..) . Il soumettra un ensemble de tâches à l’exécuteur et le bloquera jusqu’à la fin de la dernière (avec succès / avec une exception). Il retourne ensuite une liste d’objects Future terminés. Vous pouvez ainsi les afficher en boucle et fusionner les résultats dans un seul ResultObject.

Si vous souhaitez exécuter une seule tâche de manière synchrone, vous pouvez utiliser les éléments suivants:

 executor.invokeAll(Collections.singleton(task)); 

–modifier–

Maintenant, je pense que je comprends mieux vos besoins. Je suppose que vous avez besoin d’un moyen de soumettre des séquences de tâches indépendantes. Veuillez regarder le code que j’ai posté dans cette réponse .