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?

30
demandé sur Hearen 2014-12-31 19:12:58

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.

48
répondu wassgren 2017-03-07 23:11:23

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())

2
répondu user3016425 2018-05-22 18:54:17