title: Why is CompletableFuture join/get faster in separate streams than using one stream
body: <p>For the following program I am trying to figure out why using 2 different streams parallelizes the task and using the same stream and calling join/get on the Completable future makes them take longer time equivalent to as if they were sequentially processed).</p>
  
  <pre class="lang-java prettyprint-override"><code>public class HelloConcurrency {
  
      private static Integer sleepTask(int number) {
          System.out.println(String.format("Task with sleep time %d", number));
          try {
              TimeUnit.SECONDS.sleep(number);
          } catch (InterruptedException e) {
              e.printStackTrace();
              return -1;
          }
          return number;
      }
  
      public static void main(String[] args) {
          List&lt;Integer&gt; sleepTimes = Arrays.asList(1,2,3,4,5,6);
          System.out.println("WITH SEPARATE STREAMS FOR FUTURE AND JOIN");
          ExecutorService executorService = Executors.newFixedThreadPool(6);
          long start = System.currentTimeMillis();
          List&lt;CompletableFuture&lt;Integer&gt;&gt; futures = sleepTimes.stream()
                  .map(sleepTime -&gt; CompletableFuture.supplyAsync(() -&gt; sleepTask(sleepTime), executorService)
                          .exceptionally(ex -&gt; { ex.printStackTrace(); return -1; }))
                  .collect(Collectors.toList());
          executorService.shutdown();
          List&lt;Integer&gt; result = futures.stream()
                  .map(CompletableFuture::join)
                  .collect(Collectors.toList());
          long finish = System.currentTimeMillis();
          long timeElapsed = (finish - start)/1000;
          System.out.println(String.format("done in %d seconds.", timeElapsed));
          System.out.println(result);
  
          System.out.println("WITH SAME STREAM FOR FUTURE AND JOIN");
          ExecutorService executorService2 = Executors.newFixedThreadPool(6);
          start = System.currentTimeMillis();
          List&lt;Integer&gt; results = sleepTimes.stream()
                  .map(sleepTime -&gt; CompletableFuture.supplyAsync(() -&gt; sleepTask(sleepTime), executorService2)
                          .exceptionally(ex -&gt; { ex.printStackTrace(); return -1; }))
                  .map(CompletableFuture::join)
                  .collect(Collectors.toList());
          executorService2.shutdown();
          finish = System.currentTimeMillis();
          timeElapsed = (finish - start)/1000;
          System.out.println(String.format("done in %d seconds.", timeElapsed));
          System.out.println(results);
      }
  }
  </code></pre>
  
  <p>Output</p>
  
  <pre><code>WITH SEPARATE STREAMS FOR FUTURE AND JOIN
  Task with sleep time 6
  Task with sleep time 5
  Task with sleep time 1
  Task with sleep time 3
  Task with sleep time 2
  Task with sleep time 4
  done in 6 seconds.
  [1, 2, 3, 4, 5, 6]
  WITH SAME STREAM FOR FUTURE AND JOIN
  Task with sleep time 1
  Task with sleep time 2
  Task with sleep time 3
  Task with sleep time 4
  Task with sleep time 5
  Task with sleep time 6
  done in 21 seconds.
  [1, 2, 3, 4, 5, 6]
  </code></pre>