¿Cuál es la forma recomendada de esperar hasta que finalicen los subprocesos futuros Completables?

3 minutos de lectura

avatar de usuario de user2121
usuario2121

estoy usando CompletableFuture como se muestra a continuación en el código. Pero con respecto a la forma en que debo esperar hasta que finalicen todos los ejecutables, encontré dos formas y no sé la diferencia entre ellas y cuál es la mejor práctica. Son los siguientes:

Código:

this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedSERun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);
this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedNWRun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);
this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedNERun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);
this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedSWRun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);

Primer enfoque para esperar hasta que terminen todos los ejecutables:

this.growSeedExecutor.shutdown();
this.growSeedExecutor.awaitTermination(1, TimeUnit.DAYS);

Segundo enfoque para esperar hasta que terminen todos los ejecutables:

CompletableFuture.allOf(this.growSeedFutureList).join();

Por favor, hágame saber cuál es el recomendado.

  • Ambos funcionarían, por lo que depende de lo que quiera hacer con el ejecutor: si ya no lo necesita, use el primero; si desea reutilizarlo, use el último … También en su primer fragmento de código solo mantener una referencia al último CompletableFuture…

    – asilias

    8 de junio de 2015 a las 10:05

  • no entendí muy bien this.growSeedFutureList = . ¿Cuál es el tipo de growSeedFutureList ? ¿Es esta una nueva sintaxis de agregar elementos a la lista? ¿Alguien puede aclarar? ¿Hay alguna manera de lograr esto sin tener una lista?

    – Albatros

    16/09/2021 a las 18:35

Si realmente desea esperar en todos los futuros, simplemente puede llamar join() en cada uno de ellos:

growSeedFutureList.forEach(CompletableFuture::join);

La principal diferencia en comparación con el uso allOf() es que esto lanzará una excepción tan pronto como llegue a un futuro completado con una excepción, mientras que el allOf().join() La versión solo arrojará una excepción después de que se hayan completado todos los futuros (excepcionalmente o no).

Otra pequeña diferencia es que esto no crea el intermediario allOf escenario. Tal etapa sigue siendo útil si desea hacer algo de forma asincrónica después de que se hayan completado todos los futuros, en lugar de simplemente esperar a que se completen todos.

La solución con el ejecutor del otro lado tiene varios inconvenientes:

  • impide reutilizar el ejecutor ya que requiere su apagado;
  • requiere que uses ese ejecutor para todas las operaciones; no funcionará con CompletableFutures que se gestionan de otra forma;
  • no muestra claramente su intención, que es esperar a que se completen todos los futuros;
  • es más complejo de implementar;
  • no maneja la terminación excepcional – ninguna excepción será lanzada por awaitTermination() si una de las tareas falla.

Ambas formas son equivalentes solo cuando el ejecutor (growSeedExecutor) se usa únicamente para la tarea dada. La primera forma puede conducir a lo siguiente: otras tareas necesitan paralelización y se crea un nuevo ejecutor para cada tarea. Algunos desarrolladores ven que se crearon demasiados ejecutores y deciden usar un solo ejecutor común, pero no pudieron eliminar todos los ejecutores apagados…

Entonces, la segunda forma (join()) es más confiable, ya que es menos compleja. Pero cada nuevo futuro debe agregarse a growSeedFutureList, no asignarse.

Un poco tarde para la respuesta, pero espero que este código ayude a alguien que busca. Esto usa el ejecutor de grupo común forkJoin

package com.company;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String args[]){
        List<CompletableFuture> futureList=new ArrayList<>();
        for(int i=0;i<10;i++) {
            futureList.add(CompletableFuture.supplyAsync(()->getThreadName()).thenAccept(name->printThreadName(name)));
        }
        futureList.forEach(CompletableFuture::join);
    }

    static String getThreadName(){
        String threadDetails=Thread.currentThread().getName();
        System.out.println("thread deteails::::"+threadDetails);
        return threadDetails;
    }
    static void printThreadName(String value){
        System.out.println("thread string value::"+value);
    }
}

¿Ha sido útil esta solución?