-1

I am trying to execute an async operation which awaits multiple other async operations. How exactly do I do this with CompletableFutures?

Here's what I want to achieve without calling join, I actually want that those triggered operations run async to each other.

myDatabaseOperation.thenApplyAsync(){

   for(var i = 0; i < 3; i++) triggerOtherAsyncOperations();
   // Await triggered operations...

   return calculatedValueFromOperations;
}

Here's what I got so far. The problem is that CompletableFuture.allOf() does not work as intended. It simply does not block the async operation and continues, which breaks the future.

var queryTask = database.getAsync("select i from Identity i where i.id in "+list.toString(), Identity.class);
var loadComponentsTask = queryTask.thenApplyAsync(identities -> {

    var loadingTasks = new HashSet<CompletableFuture<Set<Integer>>>();
    var typeIDs = HibernateComponentUtils.mergeByComponents(identities, prototypeHierachy::get);

    // Start all loading tasks
    for(var entry : typeIDs.entrySet()){

        var sqlList = HibernateQueryUtils.toSQLList(entry.getValue());
        var loadingTask = loadEntitiesAsync(entry.getKey(), " where identity.id in "+sqlList);
        loadingTasks.add(loadingTask);
    }

    // Await all started loading tasks without blocking the mainthread
    var loadingTasksArray = loadingTasks.toArray(CompletableFuture[]::new);
    CompletableFuture.allOf(loadingTasksArray);

    // Add all loaded entities from each task to a set
    var loadedEntities = new HashSet<Integer>();
    for(var task : loadingTasks) loadedEntities.addAll(task.join());
    return (Set<Integer>)loadedEntities;
});

return loadComponentsTask;

Am I doing it wrong? What did I miss? What is the proper way to await async operations inside an async operation?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
genaray
  • 1,080
  • 1
  • 9
  • 30

1 Answers1

1

CompletableFuture.allOf(...) is not suppose to block. It returns a CompletableFuture and if you want to wait you can call join/get.

CompletableFuture.allOf(...).join();

But this is not the best solution.

I think a better solution is this:

 var loadComponentsTask = queryTask.thenComposeAsync(identities -> {
            ...
            return CompletableFuture.allOf(loadingTasksArray)
                .thenApply( v -> {
                   // Add all loaded entities from each task to a set
                   var loadedEntities = new HashSet<Integer>();
                   for(var task : loadingTasks) {
                           loadedEntities.addAll(task.join());
                   }
                   return (Set<Integer>) loadedEntities;
                });
        });
Davide D'Alto
  • 7,421
  • 2
  • 16
  • 30