es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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>, 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?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Sí, llamar a thenRunAsync es una forma correcta de ejecutar las tareas future1, future2 y future3 de forma asíncrona. Sin embargo, el método thenRunAsync toma sólo un parámetro Runnable, lo que significa que no puedes pasar las llamadas future1.join(), future2.join() y future3.join() como argumentos separados.

    Para resolver este problema, puedes crear un único Runnable que llame a los tres métodos join y pasarlo al método thenRunAsync. Aquí tienes un ejemplo:

    Runnable tareaCombinada = () -> {
        future1.join();
        future2.join();
        future3.join();
    };
    combinedFuture.thenRunAsync(tareaCombinada);
    

    Alternativamente, puedes utilizar el método CompletableFuture.allOf para combinar las tareas future1, future2 y future3 y luego utilizar el método CompletableFuture.join para esperar a que todas las tareas se completen:

    CompletableFuture<void> todasLasFuturas = CompletableFuture.allOf(future1, future2, future3);
    todasLasFuturas.join();
    

    Ambos enfoques ejecutarán las tareas future1, future2 y future3 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 una List. Sin embargo, si no te interesa el resultado de las futuras combinadas, simplemente puedes llamar a forEach(CompletableFuture::join) en lugar de usar el método collect.

    En resumen, para ejecutar las tres llamadas a la base de datos de forma asíncrona, puedes utilizar tanto el método thenRunAsync con un Runnable combinado como el método allOf con el método join. Ambos enfoques ejecutarán las tareas en diferentes hilos.

Comments are closed.