Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

487
Vistas
CompletableFuture.allOff se completa incluso si un CompletableFuture en su lista aún no está terminado

Tengo 2 Futuros Completables. La tarea 2 solo debe comenzar una vez que finaliza la tarea 1 . Luego, necesito esperar a que terminen todas las tareas. En mi código a continuación, el programa finaliza después de que finaliza task1 . La tarea 2 comienza pero no finaliza. ¿Alguna idea de por qué sucede esto? Además, ¿por qué la lista solo contiene 1 entrada mientras que en el código agregué 2?

Código:

 public void testFutures () throws Exception { List<CompletableFuture<Void>> futures = new ArrayList<>(); CompletableFuture<Void> task1 = CompletableFuture.supplyAsync( () -> { System.out.println(" task1 start"); try { Thread.sleep(5000L); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println(" task1 done"); return null; }); task1.whenComplete( (x, y) -> { CompletableFuture<Void> task2 = CompletableFuture.supplyAsync( () -> { System.out.println(" task2 start"); try { Thread.sleep(2000L); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println(" task2 done"); return null; }); futures.add(task2); }); futures.add(task1); // wait for the calls to finish try { CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).whenComplete( (x, y) -> { System.out.println(" all tasks done " + futures.size()); }).get(); } catch (Exception e) { e.printStackTrace(); } }

Producción:

 task1 start task1 done all tasks done 1 task2 start
over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Primero vamos a limpiar tu código.

Definamos un método que hará el sueño, para que no enturbie el agua:

 private static void sleep(int seconds) { try { Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); } catch (InterruptedException ex) { throw new RuntimeException(ex); } }

Luego, separemos las tareas y usemos los métodos adecuados:

 private static CompletableFuture<Void> task1() { return CompletableFuture.runAsync(() -> { System.out.println(" task1 start"); sleep(5); System.out.println(" task1 done"); }); } private static CompletableFuture<Void> task2() { return CompletableFuture.runAsync(() -> { System.out.println(" task2 start"); sleep(2); System.out.println(" task2 done"); }); }

Debe comprender que el encadenamiento de métodos CompletableFuture ya hace exactamente lo que desea, ejecutan la siguiente etapa, después de que finaliza la anterior . Puede hacer que su código sea mucho, mucho más fácil con:

 public static void main(String[] args) throws Exception { testFutures(); } private static void testFutures() throws Exception { CompletableFuture<Void> both = task1().thenCompose(ignoreMe -> task2()); both.get(); System.out.println("both done"); }
over 4 years ago · Santiago Trujillo Denunciar

0

Tienes dos problemas.

Primero, ha creado una condición de carrera en cuanto a cuándo se agrega task2 a su lista de futuros. En el momento de ejecutar esta línea—

 CompletableFuture.allOf(...).get();

—que llamaré getter de terminación , solo tiene task1 en la lista. Compruébelo usted mismo mostrando su tamaño:

 // wait for the calls to finish try { System.out.println("# of futures: " + futures.size()); // 1

task2 aún se ejecuta eventualmente , porque lo programó con whenComplete() . Pero no es su captador de terminación lo que lo desencadena.

Recuerde que dije que es una condición de carrera. Para demostrar esto por sí mismo, agregue un sleep() antes del captador de terminación, así:

 try { Thread.sleep(6000L); } catch (InterruptedException ex) { ex.printStackTrace(); } // wait for the calls to finish try { System.out.println("# of futures: " + futures.size()); // 2

Entonces le habrá dado suficiente tiempo para agregar task2 .

Pero aquí está la cosa. Ahora , ¿el captador de terminación activa ambas tareas?

¡Aún no! Y ese es el segundo problema: casi siempre desea usar uno de los thenRun() , thenAccept() , thenApply() , thenCompose() . Estos métodos encadenan sus futuros, es decir , hacen que cada etapa dependa de la anterior, de modo que su captador de terminación realmente espere a que se complete toda la cadena. whenComplete() es un método especial que inicia una canalización totalmente no relacionada y, por lo tanto, no se ve afectado por la terminación get() .

En su caso, desea usar thenRun() , así:

 task1.thenRun( ignore -> {

Bien, entonces, ¿cómo combinamos todo eso?

 public static void testFutures () throws Exception { CompletableFuture<Void> task1 = CompletableFuture.supplyAsync( () -> { System.out.println(" task1 start"); try { Thread.sleep(5000L); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println(" task1 done"); return null; }); CompletableFuture<Void> futuresChain = task1.thenRun( () -> { System.out.println(" task2 start"); try { Thread.sleep(2000L); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println(" task2 done"); }); // wait for the calls to finish try { futuresChain.thenRun( () -> { System.out.println(" all tasks done "); }).toCompletableFuture().get(); } catch (Exception e) { e.printStackTrace(); } }

Producción:

 task1 start task1 done task2 start task2 done all tasks done

Verá, solo necesita supplyAsync() para la primera tarea. Desea ejecutar task2 secuencialmente después de esa tarea, entonces thenRun() hará la programación (el supplyAsync() ) por usted. Por lo tanto, tampoco necesita una serie de futuros. allOf() es para cuando desea ejecutar tareas en paralelo y esperar a que finalicen todas.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda