Actually, if your main thread doesn't wait on the CompletableFuture
's .get()
or any other blocking method, then it dies as soon as it reaches the end of the main
method.
You can check it using the following example:
public static void main(String[] args){
final Thread mainThread = Thread.currentThread();
ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture
.supplyAsync(()-> {
try {
Thread.sleep(1000);
//prints false
System.out.println("Main thread is alive: " + mainThread.isAlive());
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}, executor)
.thenAcceptAsync(taskResult -> {
System.out.println("LongRunning is finished");
executor.shutdown();
}, executor);
}
But the Java Virtual Machine continues to execute threads until either of the following occurs
- The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.
- All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception
that propagates beyond the run method.
It means that even though the main thread is dead, the virtual machine continues to work because all threads created by the Executors.newFixedThreadPool(10)
are non-daemon. You can read about it in the documentation of the defaultThreadFactory()
method in the Executors
class:
Each new thread is created as a non-daemon thread with priority set to
the smaller of Thread.NORM_PRIORITY and the maximum priority permitted
in the thread group