2

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?

Manikandan Kbk
  • 131
  • 1
  • 8

1 Answers1

2

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.)

iggy
  • 1,328
  • 4
  • 3
  • 1
    @ManikandanKbk Because the `ForkJoinPool` uses daemon threads by default, whereas most of the factory methods (that don't take a `ThreadFactory`) in `Executors` return thread pools that use non-daemon threads. I've closed the question as a duplicate, but let me know if you think the target doesn't answer your question. – Slaw Jul 10 '21 at 13:48
  • Thanks Slaw, really comprehensive answer in the other stackoverflow thread. Now, I've to read about daemon vs non-daemon and why there is two types of threads etc.. – Manikandan Kbk Jul 10 '21 at 16:54