title: When is CompletableFuture actually completed?
body: <p>Here's the <a href="https://stackoverflow.com/help/mcve">MCVE</a>:</p>
  
  <pre><code>public static void main(String[] args) {
      CompletableFuture&lt;String&gt; r1 = CompletableFuture.supplyAsync(() -&gt; {
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              throw new RuntimeException(e);
          }
          return "41";
      });
      CompletableFuture&lt;String&gt; r2 = CompletableFuture.supplyAsync(() -&gt; "42");
      CompletableFuture&lt;String&gt; r3 = CompletableFuture.supplyAsync(() -&gt; {
          System.out.println("I'm called.");
          return "43";
      });
      CompletableFuture.allOf(r1, r2, r3).thenRun(() -&gt; { System.out.println("End."); });
      Stream.of(r1, r2, r3).forEach(System.out::println);
  }
  </code></pre>
  
  <p>Somewhat curiously, without actually completing the <code>CompletableFuture</code> from <code>allOf(...)</code>, e.g. calling its <code>join()</code>, I get the following output:</p>
  
  <pre><code>I'm called.
  java.util.concurrent.CompletableFuture@&lt;...&gt;[Not completed, 1 dependents]
  java.util.concurrent.CompletableFuture@&lt;...&gt;[Completed normally]
  java.util.concurrent.CompletableFuture@&lt;...&gt;[Completed normally]
  </code></pre>
  
  <p>May I know what's causing the JVM to treat/think that <code>r1</code> has <a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#getNumberOfDependents--" rel="noreferrer">1 (estimated number of) dependent <code>CompletableFuture</code></a>, while it decides to straightforwardly complete <code>r2</code> and <code>r3</code>? The only difference I can see is just the <code>try-catch</code>, so is the answer as simple as that?</p>
  
  <p>For comparison, I get the expected waiting time of 5 seconds and the following output when I actually do a <code>join()</code> at the end. If it helps, I'm encountering this on Java 8 Update 40 JVM.</p>
  
  <p>Modification:</p>
  
  <pre><code>// ...
  CompletableFuture.allOf(r1, r2, r3).thenRun(() -&gt; { System.out.println("End."); }).join();
  Stream.of(r1, r2, r3).forEach(System.out::println);
  </code></pre>
  
  <p>Output:</p>
  
  <pre><code>I'm called.
  // &lt;note: 5-second wait is here&gt;
  End.
  java.util.concurrent.CompletableFuture@&lt;...&gt;[Completed normally]
  java.util.concurrent.CompletableFuture@&lt;...&gt;[Completed normally]
  java.util.concurrent.CompletableFuture@&lt;...&gt;[Completed normally]
  </code></pre>