[concurrency-interest] Java 8 CompletableFuture.thenCombine() hangs

Paul Sandoz paul.sandoz at oracle.com
Wed Apr 2 08:06:44 EDT 2014


On Apr 2, 2014, at 1:16 AM, Dennis Sosnoski <dms at sosnoski.com> wrote:

> I've run into a situation with CompletableFuture.thenCombine() hanging (i.e., the returned future never completing even though the original future and the combined one have completed) with the Oracle Java 8 release for 64-bit Linux. I wanted to run this by the group before creating a bug report to make sure I'm not misunderstanding how this is supposed to work. Here's the code:
> 
> public class CompletableFutureFail {
> 
>    private Supplier<Integer> newLambda(int i) {
>        return () -> Integer.valueOf(i);
>    }
> 
>    private Integer run(int n) {
>        CompletableFuture<Integer> last = CompletableFuture.supplyAsync(newLambda(0));
>        for (int i = 1; i < n; i++) {
>            last = CompletableFuture.supplyAsync(newLambda(i)) .thenCombine(last, Math::max);
>        }
>        return last.join();
>    }
> 
>    public static void main(String[] args) {
>        CompletableFutureFail fail = new CompletableFutureFail();
>        for (int i = 0; i < 100; i++) {
>            fail.run(10000);
>            System.out.println("Did it " + i);
>        }
>    }
> }
> 
> When I run it from the command line it mostly doesn't make it through the first call to run(). Sometimes it does, but it generally only makes a few passes before hanging. In other circumstances (such as running inside Eclipse) I've seen it make it all the way through to the end, though most often it also hangs there in the first few passes. I'm thinking it might be Hotspot related because of the halting pattern.
> 

My gut feeling is that it is more likely to be a race condition in the CompletableFuture.thenCombine and completion linked list management code.

I cannot reproduce:

1) if there is more work to do:

    private Supplier<Integer> newLambda(int i) {
        return () -> {
            BigInteger bi = BigInteger.probablePrime(64, ThreadLocalRandom.current());
            return Integer.valueOf(bi.hashCode());
        };
    }

2) changed to use "thenCombineAsync".

Some test code below shows that all suppliers are run (also easy to set a break point within the block of "if (cld.getCount() == 1) {", to analyze data structures).

Paul.

public class Test {

    static Map<Integer, Integer> m = new ConcurrentHashMap<>();
    static List<CompletableFuture<Integer>> tasks = new ArrayList<>();

    private Supplier<Integer> newLambda(int i) {
        return () -> {
            m.put(i, i);
            return i;
        };
    }

    private Integer run(int n) {
        CompletableFuture<Integer> last = CompletableFuture.supplyAsync(newLambda(0));
        last.join();
        tasks.add(last);
        for (int i = 1; i < n; i++) {
            last = CompletableFuture.supplyAsync(newLambda(i))
                    .thenCombine(last, Math::max);
            tasks.add(last);
        }
        System.out.println(last);
        return last.join();
    }


    public static void main(String[] args) {
        Test fail = new Test();
        for (int i = 0; i < 1000000; i++) {
            m.clear();
            tasks.clear();

            CountDownLatch cld = new CountDownLatch(1);
            Thread t = new Thread(() -> {
                try {
                    cld.await(2, TimeUnit.SECONDS);
                }
                catch (InterruptedException e) {
                }

                if (cld.getCount() == 1) {
                    List<CompletableFuture<Integer>> it = tasks.stream().filter(task -> !task.isDone()).collect(toList());
                    System.out.printf("%d tasks not completed\n", it.size());
                }
            });

            t.start();
            fail.run(5000);
            cld.countDown();
            System.out.println("Did it " + i);
        }
    }
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 841 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20140402/01718113/attachment.bin>


More information about the Concurrency-interest mailing list