CompletableFuture, supplyAsync () et thenApply()
Besoin de confirmer quelque chose. Le code suivant:
CompletableFuture
.supplyAsync(() -> {return doSomethingAndReturnA();})
.thenApply(a -> convertToB(a));
Serait le même que:
CompletableFuture
.supplyAsync(() -> {
A a = doSomethingAndReturnA();
convertToB(a);
});
Pas Vrai?
En outre, deux autres questions suivantes comme pour " y a-t-il une raison pour laquelle nous utiliserions thenApply
?"
1) avoir un gros code pour la conversion?
Ou
2) besoin de réutiliser le bloc lambda dans d'autres endroits?
2 réponses
Ce n'est pas la même chose . Dans le deuxième exemple où thenApply
n'est pas utilisé, il est certain que l'appel de convertToB
est exécuté dans le même fil que la méthode doSomethingAndReturnA
.
Mais, dans le premier exemple, lorsque la méthode thenApply
est utilisée, d'autres choses peuvent arriver.
Tout d'abord, si le CompletableFuture
qui exécute le doSomethingAndReturnA
est terminé, l'appel du thenApply
se produira dans le thread appelant. Si le CompletableFutures
n'a pas été terminé, le Function
passé à {[3] } sera appelé dans le même thread que doSomethingAndReturnA
.
Déroutant? Eh bien cet article pourrait être utile (Merci @SotiriosDelimanolis pour le lien).
J'ai fourni un court exemple qui illustre comment fonctionne thenApply
.
public class CompletableTest {
public static void main(String... args) throws ExecutionException, InterruptedException {
final CompletableFuture<Integer> future = CompletableFuture
.supplyAsync(() -> doSomethingAndReturnA())
.thenApply(a -> convertToB(a));
future.get();
}
private static int convertToB(final String a) {
System.out.println("convertToB: " + Thread.currentThread().getName());
return Integer.parseInt(a);
}
private static String doSomethingAndReturnA() {
System.out.println("doSomethingAndReturnA: " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "1";
}
}
Et la sortie est:
doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1
convertToB: ForkJoinPool.commonPool-worker-1
Ainsi, lorsque la première opération est lente (c'est-à-dire que CompletableFuture
n'est pas encore terminée), les deux appels se produisent dans le même thread. Mais si nous devions supprimer l'appel Thread.sleep
du doSomethingAndReturnA
, la sortie (peut) être comme ce:
doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1
convertToB: main
Notez que l'appel convertToB
est dans le thread main
.
thenApply()
est une fonction de rappel qui sera exécuté lorsque supplyAsync()
retourner une valeur.
Dans l'extrait de code 2, le thread qui a invoqué doSomethingAndReturnA()
attend que la fonction soit exécutée et renvoie les données.
Mais dans certains cas exceptionnels (comme faire un appel Webservice et attendre une réponse), le thread doit attendre long temps pour obtenir la réponse, ce qui consomme beaucoup de ressources de calcul du système (juste en attente de réponse).
Pour éviter cela, CompletableFuture
livré avec la fonctionnalité callback , où une fois que le doSomethingAndReturnA()
est invoqué, un thread séparé s'occupera de l'exécution de doSomethingAndReturnA()
et le thread appelant principal continuera à effectuer d'autres opérations sans attendre le retour de la réponse.
Une fois la réponse de doSomethingAndReturnA
disponible, la méthode de rappel sera appelée (c'est-à-dire, thenApply()
)