When does the main thread stop in Java?
The program terminates when all non-daemon threads die (a daemon thread is a thread marked with setDaemon(true)
; it's usually used for utility threads). From the documentation:
When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). 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.
how to stop main thread while another thread still running
Regular Threads can prevent the VM from terminating normally (i.e. by reaching the end of the main method - you are not using System#exit() in your example, which will terminate the VM as per documentation).
For a thread to not prevent a regular VM termination, it must be declared a daemon thread via Thread#setDaemon(boolean) before starting the thread.
In your example - the main thread dies when it reaches the end of it code (after t1.start();), and the VM - including t1- dies when t1 reaches the end of its code (after the while(true) aka never or when abnormally terminating.)
Compare this question, this answer to another similar question and the documentation.
Java - Stop a thread automatically when program ends
The thread you are creating is independent and does not depend on the Main Thread termination. You can use Daemon
thread for the same. Daemon threads will be terminated by the JVM when there are none of the other non- daemon threads running, it includes a main thread of execution as well.
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("Daemon thread");
}
}
});
t.setDaemon(true);
t.start();
System.out.println("End of main");
}
Why the main thread doesn't terminate when there is a completion stage that has not been completed?
I added time marks to the output of your program and also a shutdown hook so that JVM termination can be logged as well:
0s Hello from thread: main # `main` method starts
0s I am in the thread: pool-1-thread-1 # `Runnable` submitted to the executor starts
0s I am dying ... # `main` method exits
50s I am done, and my value is 6 # `Runnable` submitted to the executor finishes
110s exiting # JVM process exits
Non-daemon threads
The reason why the process continues after main
method exits is that JVM needs to wait for all non-daemon threads to terminate before it shuts down. Executors produced using Executors class create non-daemon threads by default (see Executors.defaultThreadFactory() method javadoc).
Customizing ThreadFactory
You can override how the threads are created by passing a custom ThreadFactory to the Executors.newCachedThreadPool() method:
ExecutorService executorService = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t;
});
executorService
will only have daemon threads in its thread pool.
Thread caching
But notice that the JVM still doesn't exit for 60 seconds after your thenAccept
block is executed:
50s I am done, and my value is 6 # `Runnable` submitted to the executor finishes
110s exiting # JVM process exits
Why is that? It's explained in Executors.newCachedThreadPool() documentation (emphasis added):
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. Calls to execute will reuse previously constructed threads if available. If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache. Thus, a pool that remains idle for long enough will not consume any resources. Note that pools with similar properties but different details (for example, timeout parameters) may be created using ThreadPoolExecutor constructors.
This means that this thread pool does not dispose of the threads immediately after they finish doing scheduled tasks. It will instead do it's best to reuse previously created threads for new task submissions. This is the reason for the delay: after your task finishes the thread remains in the thread pool for reusal and only after the next 60 seconds it is destroyed (you only submit one task in your program). Only then the JVM can exit (because the thread is not a daemon thread as pointed above).
Shutting down the ExecutorService
Normally when working with an ExecutorService you should shut it down explicitly before the process is terminated. For this purpose use ExecutorService.shutdown() or ExecutorService.shutdownNow() methods. Refer to the documentation for the difference between these two.
References
What is a daemon thread in Java?
Turning an ExecutorService to daemon in Java
Program does not terminate immediately when all ExecutorService tasks are done
Modified program with time marks and JVM termination log:
public class Main {
private static final Instant start = Instant.now();
private static void debug(String message) {
System.out.println(Duration.between(start, Instant.now()).getSeconds() + "s " + message);
}
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> debug("exiting")));
debug("Hello from thread: "+Thread.currentThread().getName());
new Game().run();
debug("I am dying ... ");
}
static class Game {
public void run() {
value();
}
private int value() {
int number = 0;
CompletionStage<Void> c = calculate().thenApply(i -> i + 3).thenAccept(i -> debug("I am done, and my value is " + i));
return number;
}
private CompletionStage<Integer> calculate() {
CompletionStage<Integer> completionStage = new CompletableFuture<>();
Executors.newCachedThreadPool().submit(() -> {
debug("I am in the thread: " + Thread.currentThread().getName());
try {
Thread.sleep(50000);
((CompletableFuture<Integer>) completionStage).complete(3);
} catch (Exception e) {
e.printStackTrace();
}
return null;
});
return completionStage;
}
}
}
How can thread run after main method closes?
Your main
thread is not closed -
// ...
System.out.println("Main close...");
// <--- Your main method is here while all the other threads complete (sort of).
}
On part 2 of your question - There is no connection between join
and synchronized
. They are almost opposite.
join
- Wait for the thread to complete before resuming.synchronized
- Only one thread can enter here, all others must wait.
java: why main thread waits for child thread to finish
The main thread has exited. It's the other thread that's still alive.
will main thread exit before child threads complete execution?
Java makes a distinction between a user thread and another type of thread known as a daemon thread. The difference between these two types of threads is that if the JVM determines that the only threads running in an application are daemon threads (i.e., there are no user threads), the Java runtime closes down the application. On the other hand, if at least one user thread is alive, the Java runtime won't terminate your application.
When your main()
method initially receives control from the Java runtime, it executes in the context of a user thread. As long as the main-method thread or any other user thread remains alive, your application will continue to execute.
In your case, the threads are user threads and hence are allowed to complete before the main thread exits.
i am processing some files. in
testA
thread A alone, 1 file alone is
not getting processed some times. but many times
The reason for the above is could be something else than thread exits. It could be file locks, synchronization issue etc.
Thread (Java SE 10 & JDK 10):
When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named
main
of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs:
- The
exit
method of classRuntime
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 therun
method.
Why does a thread outlive the main method in Java?
If you want your program to exit when the main method finished, consider making your threads daemons. But take care of the fact, that daemon threads will be aborted, when main finishes.
You can create a daemon thead like so:
Thread t = new Thread(...);
t.setDaemon(true);
All non-daemon threads are user threads. Those threads are stopping the jvm from closing.
Related Topics
Preparedstatement Syntax Error
How to Identify Contents of a Byte[] Is a Jpeg
Ssl Peer Shut Down Incorrectly in Java
Accessing Post Variables Using Java Servlets
How Java Do the String Concatenation Using "+"
How to Add Days to a Date in Java
How to Create a New Packaging Type for Maven
Use of the Manifest.Mf File in Java
Java.Lang.Nosuchmethoderror in Flink
What Is the Point of Getters and Setters
Multiple Inheritance for an Anonymous Class
How Do Determine If an Object Is Locked (Synchronized) So Not to Block in Java
In Java, Differencebetween This.Method() and Method()
How to Save Parsed and Changed Dom Document in Xml File
Generating All Possible Permutations of a List Recursively
Java User.Home Is Being Set to %Userprofile% and Not Being Resolved