Why is CompletableFuture.supplyAsync succeeding a random number of times?

By default CompletableFuture uses own ForkJoinPool.commonPool() (see CompletableFuture implementation). And this default pool creates only daemon threads, e.g. they won’t block the main application from terminating if they still alive.

You have the following choices:

  1. Collect all CompletionStage to some array and then make java.util.concurrent.CompletableFuture#allOf().toCompletableFuture().join() – this will guarantee all the stages are completed before going after join()

  2. Use *Async operations with your own thread pool which contains only non-daemon threads, like in the following example:

    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(10, r -> {
            Thread t = new Thread(r);
            t.setDaemon(false); // must be not daemon
            return t;
        });
    
        for (int i = 0; i < 100; i++) {
            final int a = i;
    
            // the operation must be Async with our thread pool
            CompletableFuture<Boolean> cf = CompletableFuture.supplyAsync(() -> doPost(a), pool);
            cf.thenRun(() -> System.out.printf("%s: Run_%s%n", Thread.currentThread().getName(), a));
        }
    
        pool.shutdown(); // without this the main application will be blocked forever
    }
    
    private static boolean doPost(int t) {
        System.out.printf("%s: Post_%s%n", Thread.currentThread().getName(), t);
    
        return true;
    }
    

Leave a Comment