title: Huge delay in CompletableFuture join() method
body: <p>So I'm working on an application that has to make 20+ HTTP calls at a time. Each one of them takes 2-3 seconds to get a response.  It's pretty slow to make these calls one at a time (40 seconds at best), so I am trying to send them asynchronously via CompletableFutures. This should allow me to make calls while I'm waiting for the response of others, in theory reducing the total time to maybe 4-5 seconds instead of 40.</p>
  
  <p>I made a very similar setup to this tutorial I found at <a href="https://www.codepedia.org/ama/how-to-make-parallel-calls-in-java-with-completablefuture-example" rel="nofollow noreferrer">https://www.codepedia.org/ama/how-to-make-parallel-calls-in-java-with-completablefuture-example</a>.</p>
  
  <pre><code>import org.codingpedia.example;
  
  import javax.inject.Inject;
  import java.util.List;
  import java.util.concurrent.CompletableFuture;
  import java.util.function.Supplier;
  import java.util.stream.Collectors;
  
  public class ParallelCallsDemoService {
  
      @Inject
      RestApiClient restApiClient;
  
      private ExecutorService es = Executors.newFixedThreadPool(20);
  
      public List&lt;ToDo&gt; getToDos(List&lt;String&gt; ids){
  
          List&lt;CompletableFuture&lt;ToDo&gt;&gt; futures =
                  ids.stream()
                            .map(id -&gt; getToDoAsync(id))
                            .collect(Collectors.toList());
  
          List&lt;ToDo&gt; result =
                  futures.stream()
                          .map(CompletableFuture::join)
                          .collect(Collectors.toList());
  
          return result;
      }
  
  
      CompletableFuture&lt;ToDo&gt; getToDoAsync(String id){
  
          CompletableFuture&lt;ToDo&gt; future = CompletableFuture.supplyAsync(() -&gt; {
              return restApiClient.makeSomeHttpCall(id);
          }, es);
  
          return future;
      }
  
  }
  </code></pre>
  
  <p>By all accounts it seems to be working - the calls all get sent at roughly the same time, and they all return in a couple seconds. But then I'm experiencing a huge delay of 30-40 seconds on this part: </p>
  
  <pre><code>        List&lt;ToDo&gt; result =
                  futures.stream()
                          .map(CompletableFuture::join)
                          .collect(Collectors.toList());
  </code></pre>
  
  <p>This makes it take roughly the same time as sending serially, which baffles me.  How can it be that I'm getting all responses in a couple seconds but then there's a 30 second delay on joining them? It's almost as if (despite appearances) they're still being made serially. Why does the join take so long?</p>