JDK-8201576 : REOPEN: CompletableFuture join hangs forever while all dependents are in completed stage
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.concurrent
  • Affected Version: 8u172
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86_64
  • Submitted: 2018-04-13
  • Updated: 2018-04-16
  • Resolved: 2018-04-16
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE PROBLEM :
This is a duplicate of https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8200347#

Not clear why this was closed. As the test case works eventually. We have hit the issue in production.

More details can be found at the original bug.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached test case on Java 8 u 162 or 172.  It will eventually hang.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
CompletableFuture joins eventually
ACTUAL -
CompletableFuture never joins

---------- BEGIN SOURCE ----------
import java.util.ArrayList;
import java.util.concurrent.*;

public class Main {
    public static void main(String... args) {
        test();
    }

    private static void safeRandomSleep(int i) {
        try {
            Thread.sleep(ThreadLocalRandom.current().nextInt(i));
        } catch (InterruptedException e) {

        }
    }

    private static void test() {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 10_000_000; i++) {

            CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
                safeRandomSleep(10);
                return "S";
            }, executor);

            CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
                safeRandomSleep(10);
                throw new RuntimeException("123");
            }, executor);

            ArrayList<CompletableFuture<?>> ff = new ArrayList<>();
            ff.add(f1);
            ff.add(f2);

            for (int j = 0; j < 3; j++) {
                ff.add(f1.thenCombineAsync(f2, (s1, s2) -> s1 + s2, executor));
                ff.add(f1.thenApplyAsync((s) -> s, executor));
            }

            CompletableFuture[] ff1 = new CompletableFuture[8];
            ff1[0] = ff.get(4);
            ff1[1] = ff.get(7);
            ff1[2] = ff.get(6);
            ff1[3] = ff.get(3);
            ff1[4] = ff.get(2);
            ff1[5] = ff.get(1);
            ff1[6] = ff.get(0);
            ff1[7] = ff.get(5);

            CompletableFuture<Void> all = CompletableFuture.allOf(ff1);
            all.whenComplete((aVoid, throwable) -> System.out.print("."));

            safeRandomSleep(10);

            CompletableFuture[] ff2 = new CompletableFuture[8];
            ff2[0] = ff.get(6);
            ff2[1] = ff.get(0);
            ff2[2] = ff.get(5);
            ff2[3] = ff.get(7);
            ff2[4] = ff.get(2);
            ff2[5] = ff.get(1);
            ff2[6] = ff.get(3);
            ff2[7] = ff.get(4);

            CompletableFuture<Void> all2 = CompletableFuture.allOf(ff2);
            all2.whenComplete((aVoid, throwable) -> System.out.print("."));

            try {
                CompletableFuture<Void> a = all.thenApplyAsync(s -> s, executor);
                CompletableFuture<Void> b = all2.thenApplyAsync(s -> s, executor);
                a.join();
                b.join();
            } catch (Exception e) {
            }
            System.out.println(i);
        }

    }

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Doing timed gets in a loop worked for us.

FREQUENCY : rarely



Comments
I decided not to try to backport CompletableFuture changes to jdk8u because the backport will be non-trivial and the changes in jdk9+ seemed a little risky at that time. But that was from before it was known that the lifetime of jdk8u would be longer than expected, and people are happy with the state of CompletableFuture at head ...
16-04-2018

Sent mail to submitter: The issue https://bugs.openjdk.java.net/browse/JDK-8200347 was closed as Cannot Reproduce, as it is not reproducible in the latest JDK version JDK 10+46 and seems to have been fixed in it. As you can see at the link http://www.oracle.com/technetwork/java/javase/overview/index.html , the JDK 8 updates will not be posted to the Oracle download site after January 2019 and only critical issues/security issues will be backported to JDK 8. Can you please verify if you are able to reproduce the issue with the latest JDK version 10+46 ?
16-04-2018

This is basically asking for a backport of whatever fixes the issue in JDK 10, to JDK 8u.
16-04-2018