I often read in Java blogs that main thread is the last thread to die after all other threads die. This is obviously not what I experience. Main thread dies right after it finishes its business, leaving the threads that main spawned working alone. Moreover, if main spawns ThreadA, for example, and main joins ThreadA using Thread.join() method, then main only waits until ThreadA dies, then main dies. If in the process of running ThreadA spawns some other threads, then when ThreadA and main dies, those other threads will keep running if their business is not finished yet.
Interesting comment from
this website:
The main()
method must indeed have a void
return type. From the Java Language Specification on "Execution - Virtual Machine Start-Up" (§12.1.4): The method main
must be declared public
, static
, and void
. It must accept a single argument that is an array of strings.
A program terminates all its activity and exits when one of two things happens:
- All the threads that are not daemon threads terminate.
- Some thread invokes the
exit
method of class Runtime
or class System
and the exit operation is not forbidden by the security manager.
In other words, the program may exit before or after the main
method finishes; a return value frommain
would therefore be meaningless. Therefore the return value of main is void.
main() method has no control over JVM. When JVM starts, it will run main() method, but when main() finishes, it doesn't mean that JVM terminaes. JVM continues to execute all threads until 1) Runtime.exit() is called OR 2) all normal (not daemon) threads have died. Daemon threads do not count for this second condition. In other words ... if main() method spawns some normal threads, JVM will notterminate when main() finishes. If main() doesn't spawn any threads, JVM will terminate. If main() spawns only daemon threads, JVM will also terminate when main() finishes.
Compile and run the following code:
package test;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
public class ThreadTest {
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
System.out.println("The current main thread: "
+ Thread.currentThread().getName());
printAllThreads();
ThreadA tc = new ThreadA();
tc.start();
tc.join();
// Thread.sleep(5000);
System.out.println("Exiting main thread.");
}
static private void printAllThreads() {
Map stackTraces = Thread
.getAllStackTraces();
Set< Entry> entrySet = stackTraces
.entrySet();
for (Entry entry : entrySet) {
Thread t = entry.getKey();
System.out.println(">>>>>>>>>> " + t.getName());
}
}
}
----------------------------------------------------------
package test;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
public class ThreadA extends java.lang.Thread {
private volatile int counterA = 0;
public ThreadA(){
setName("Threadcounter");
}
public void run() {
while (counterA < 10) {
System.out.println("Printing from within ThreadA: " + counterA++);
printAllThreads();
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
ThreadB pt = new ThreadB();
pt.start();
System.out.println("Exiting ThreadA.");
}
private void printAllThreads() {
Map stackTraces = Thread
.getAllStackTraces();
Set< Entry> entrySet = stackTraces
.entrySet();
for (Entry entry : entrySet) {
Thread t = entry.getKey();
System.out.println(">>>>>>>>>> Printing From ThreadCounter: "
+ t.getName());
}
}
private class ThreadB extends Thread {
private volatile int counterB = 0;
public ThreadB(){
setName("Privatethread");
}
public void run() {
while (counterB < 100) {
System.out.println("Printing from within ThreadB: " + counterB++);
printAllThreads();
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Exiting ThreadB.");
}
}
}