Cómo ejecutar CompletetableFutures combinados de forma asíncrona
Quiero cargar datos al inicio de la aplicación llamando a diferentes servicios que devuelven listas de diferentes tipos de objetos. Cada servicio llama a la clase DAO para leer algunos datos. Así que he creado objetos individuales CompletableFuture, como:
CompletableFuture<><dto1>> future1 = CompletableFuture.supplyAsync(() -> service1.callMethod1());
CompletableFuture<><dto2>> future2 = CompletableFuture.supplyAsync(() -> service2.callMethod2());
CompletableFuture<><dto3>> future3 = CompletableFuture.supplyAsync(() -> service3.callMethod3());
y los he combinado de la siguiente manera:
CompletableFuture<void> combinedFuture = CompletableFuture.allOf(future1, future2, future3);
Si hago algo como:
combinedFuture.thenRunAsync(() -> future1.join(), future2.join(), future3.join())
Entonces obtengo el error en tiempo de compilación. Soy nuevo en las características de concurrencia de Java 8, como CompletableFuture, pensé que llamar a thenRunAsync ejecutaría cada future1, future2, future3 en diferentes hilos. ¿Es la forma correcta de hacerlo llamando a thenRunAsync? Si es así, ¿cómo puedo eliminar ese error en tiempo de compilación?
Pero si hago algo como:
Stream.of(future1, future2, future3)
.map(CompletableFuture::join)
.collect(Collectors.toList());
Esto devuelve List extends List>>, parece que funciona, ¿debería llamar a .collect(Collectors.toList())? No me preocupa este resultado combinado, ya que cada llamada a los métodos individuales ya está anotada con @Cacheable para fines de almacenamiento en caché.
Además, si hago algo como:
Stream.of(future1, future2, future3)
.forEach(CompletableFuture::join);
¿Se ejecutarán future1, future2, future3 en diferentes hilos? ¿Cómo puedo ejecutar future1, future2, future3 en 3 hilos diferentes? ¿Hay alguna forma correcta de ejecutar estas tres llamadas a la base de datos de forma asíncrona?
davy.ai
Sí, llamar a
thenRunAsync
es una forma correcta de ejecutar las tareasfuture1
,future2
yfuture3
de forma asíncrona. Sin embargo, el métodothenRunAsync
toma sólo un parámetroRunnable
, lo que significa que no puedes pasar las llamadasfuture1.join()
,future2.join()
yfuture3.join()
como argumentos separados.Para resolver este problema, puedes crear un único
Runnable
que llame a los tres métodosjoin
y pasarlo al métodothenRunAsync
. Aquí tienes un ejemplo:Alternativamente, puedes utilizar el método
CompletableFuture.allOf
para combinar las tareasfuture1
,future2
yfuture3
y luego utilizar el métodoCompletableFuture.join
para esperar a que todas las tareas se completen:Ambos enfoques ejecutarán las tareas
future1
,future2
yfuture3
de forma asíncrona y en diferentes hilos.En cuanto al código
Stream.of(future1, future2, future3)
, llamar a.collect(Collectors.toList())
es necesario para convertir el stream en unaList
. Sin embargo, si no te interesa el resultado de las futuras combinadas, simplemente puedes llamar aforEach(CompletableFuture::join)
en lugar de usar el métodocollect
.En resumen, para ejecutar las tres llamadas a la base de datos de forma asíncrona, puedes utilizar tanto el método
thenRunAsync
con unRunnable
combinado como el métodoallOf
con el métodojoin
. Ambos enfoques ejecutarán las tareas en diferentes hilos.