Why does ExecutorService waits for all threads to complete but Completable future not?

Viewed 71

In this following code,

class MainX {

    static void run(int i) {
        try {
            System.out.println(i + " called");
            Thread.sleep(1000);
            String s = "";
            for (int j = 0; j < 20000; j++) {
                s = s + j;
            }
            System.out.println(i + " completed" + " " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            int p = i;
            executorService.submit(() -> MainX.run(p));
        }
        System.out.println("all called");
        executorService.shutdown();
        System.out.println("all called" + " Thr:" + Thread.currentThread().getName());
    }
}

(Vs)

class MainX {

    static void run(int i) {
        try {
            System.out.println(i + " called");
            Thread.sleep(1000);
            String s = "";
            for (int j = 0; j < 20000; j++) {
                s = s + j;
            }
            System.out.println(i + " completed" + " " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        for(int i = 0; i < 10; i++) {
            int p = i;
            CompletableFuture.runAsync(() -> MainX.run(p));
        }
    }
}

In the first case, jvm keeps on running until all the threads are completed. But in the second case, jvm and other threads are killed as soon as main thread dies.

Any reason for this?

1 Answers

From my viewpoint, 'CompletableFuture' does not itself execute anything, so it has no threads to wait for. It relies on other mechanisms for running stages.

'runAsync', without an Executor, runs tasks in its common ForkJoin pool, which is documented as having the behaviour you observe.

That doesn't answer your question of 'why', except to say that it's intentionally designed that way. I can only hand-wave and say that its designers likely considered it to be the best default choice.

(I concur: In code I've written, if I get to the point of program termination, what I want is for everything to just go away. In the rare case I need it to complete, I'd wait for it before exiting.)

Related