completionstage completablefuture await async java-8 futuretask

java-8 - completablefuture - java 8 promise



CompletableFuture, supplyAsync() y luegoApply() (2)

Necesito confirmar algo. El siguiente código:

CompletableFuture .supplyAsync(() -> {return doSomethingAndReturnA();}) .thenApply(a -> convertToB(a));

sería lo mismo que:

CompletableFuture .supplyAsync(() -> { A a = doSomethingAndReturnA(); convertToB(a); });

¿Derecha?

Además, otras dos preguntas que siguen como "¿hay alguna razón por la que thenApply ?"

1) ¿Tener código grande para la conversión?

o

2) ¿Necesitas reutilizar el bloque lambda en otros lugares?


No es lo mismo . En el segundo ejemplo en el que thenApply no se usa, es cierto que la llamada a convertToB se ejecuta en el mismo hilo que el método doSomethingAndReturnA .

Pero, en el primer ejemplo, cuando se thenApply método thenApply , pueden suceder otras cosas.

En primer lugar, si se ha completado CompletableFuture que ejecuta doSomethingAndReturnA , la invocación de thenApply se realizará en el subproceso de la persona que llama. Si no se ha completado CompletableFutures, la Function pasada a thenApply se invocará en el mismo hilo que doSomethingAndReturnA .

¿Confuso? Bueno, este artículo podría ser útil (gracias @SotiriosDelimanolis por el enlace).

He proporcionado un breve ejemplo que ilustra cómo funciona 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"; } }

Y la salida es:

doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1 convertToB: ForkJoinPool.commonPool-worker-1

Entonces, cuando la primera operación es lenta (es decir, el CompletableFuture aún no se ha completado), ambas llamadas se producen en el mismo hilo. Pero si elimináramos el Thread.sleep de doSomethingAndReturnA la salida (puede) ser así:

doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1 convertToB: main

Tenga en cuenta que la llamada convertToB está en el hilo main .


thenApply() es una función de devolución de llamada, que se ejecutará cuando supplyAsync() devuelva un valor.

En el fragmento de código 2, el subproceso que invocó a doSomethingAndReturnA() espera a que la función se ejecute y devuelva los datos.

Pero en algunos casos excepcionales (como hacer una llamada al servicio web y esperar una respuesta), el subproceso tiene que esperar mucho tiempo para obtener la respuesta, lo que consume una gran cantidad de recursos de cómputo del sistema (solo espera la respuesta).

Para evitar eso, CompletableFuture viene con la función de devolución de llamada , donde una vez que se invoca doSomethingAndReturnA() , un subproceso independiente se encargará de ejecutar doSomethingAndReturnA() y el subproceso principal del llamante continuará realizando otras operaciones sin esperar la respuesta.

Una vez que esté disponible la respuesta de doSomethingAndReturnA , se invocará el método de devolución de llamada (es decir, a thenApply() , thenApply() )