L'appel complete
déclenche tous les dépendants CompletionStage
s.
Donc, si vous avez déjà enregistré un BiConsumer
avec whenComplete
, le complete
l'appellera dans son thread appelant. Dans votre cas, l'appel au complete
reviendra lorsque le BiConsumer
que vous avez passé à whenComplete
se termine. Ceci est décrit dans les les class javadoc
possibilités fournies pour complétions dépendantes de méthodes non asynchrones peuvent être effectuée par le fil qui complète le courant CompletableFuture
, ou par tout autre appelant d'un procédé d'achèvement.
(par un autre appelant est la situation inverse, où le thread appelant whenComplete
s'appliquerait en fait le BiConsumer
si la cible CompletableFuture
avaient déjà été achevés.)
Voici un petit programme pour illustrer la comportement:
public static void main(String[] args) throws Exception {
CompletableFuture<String> future = new CompletableFuture<String>();
future.whenComplete((r, t) -> {
System.out.println("before sleep, executed in thread " + Thread.currentThread());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after sleep, executed in thread " + Thread.currentThread());
});
System.out.println(Thread.currentThread());
future.complete("completed");
System.out.println("done");
}
Ce imprimera
Thread[main,5,main]
before sleep, executed in thread Thread[main,5,main]
after sleep, executed in thread Thread[main,5,main]
done
montrant que le BiConsumer
a été appliqué dans le thread principal, celui qui a appelé complete
.
Vous pouvez utiliser whenCompleteAsync
pour forcer l'exécution de BiConsumer
dans un thread distinct.
[...] qui exécute l'action donnée en utilisant par défaut de facilité d'exécution asynchrone de cette étape lorsque cette étape complète.
Par exemple,
public static void main(String[] args) throws Exception {
CompletableFuture<String> future = new CompletableFuture<String>();
CompletableFuture<?> done = future.whenCompleteAsync((r, t) -> {
System.out.println("before sleep, executed in thread " + Thread.currentThread());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after sleep, executed in thread " + Thread.currentThread());
});
System.out.println(Thread.currentThread());
future.complete("completed");
System.out.println("done");
done.get();
}
imprimera
Thread[main,5,main]
done
before sleep, executed in thread Thread[ForkJoinPool.commonPool-worker-1,5,main]
after sleep, executed in thread Thread[ForkJoinPool.commonPool-worker-1,5,main]
montrant que le BiConsumer
a été appliqué dans un thread séparé.
Merci beaucoup. Votre explication est très claire sur le filetage. Lors de ma première utilisation de CompletableFuture, je l'utilise uniquement pour appeler une requête unique du client vers le serveur (comme SELECT, UPDATE, etc.), donc il fonctionne parfaitement comme mes attentes (le client attend la réponse et remplit le futur). Mais maintenant, j'ai un problème avec TRANSACTION parce qu'il a des étapes. Je veux renvoyer le futur immédiatement comme un CompletableFuture après que tout soit fait SELECT, mais le futur n'est rempli que lorsque d'autres exécutions (UPDATE, DELETE) ont des résultats. Pouvez-vous me proposer une solution pour traiter les choses en chaîne. Merci beaucoup! –
Je veux faire les choses dans l'ordre comme: 1. SELECT -> CompletableFuture 2. PREPARE -> CompletableFuture (faire d'autres appels ceux retournent des CompletableFutures aussi). 3. COMMIT -> CompletableFuture et la transaction doit retourner immédiatement à l'appelant lorsque je l'enregistre. Merci beaucoup! –