Java Main Thread: Understanding and Controlling the Main Execution Thread

Delve into the concept of the main thread in Java, the primary thread created automatically by the JVM to execute a program’s main method. Learn how the main thread manages the program flow, initiates child threads, and is used for shutdown tasks. Discover methods to control the main thread’s behavior in Java applications.



Java - Main Thread

Main Thread in Java

Whenever we run a Java program, the main thread is created automatically. This thread is responsible for executing the Java program. The Java runtime searches for the main method to execute and creates a main thread based on it. If we're creating multiple threads, then all child threads will be spawned from the main thread. The main thread is the first thread to be created and is generally the last thread to finish; it is used to perform shutdown tasks.

How to Control Main Thread?

The main thread is created by the JVM automatically when a program starts. However, you can control the main thread by using various thread methods and techniques. The following are some methods for controlling the main thread:

  • sleep() Method
  • join() Method
  • interrupt() Method

Example of Java Main Thread

In this example, we demonstrate a simple one-thread program where we don't declare any thread but check the thread name during execution.

Code

package com.tutorialsarena;
public class TestThread {
public void printName() {
    System.out.println("Thread Name: " + Thread.currentThread().getName());
    System.out.println("Thread Priority: " + Thread.currentThread().getPriority());
}    
public static void main(String args[]) {
    TestThread thread = new TestThread();
    thread.printName();       
}
}
Output

Thread Name: main
Thread Priority: 5

More Examples of Main Thread

Example 1

In this example, we've created a ThreadDemo class that extends the Thread class. We're not passing any name to the thread, and it will print the default names assigned to the threads by the system. In the main method, we create two threads. In the output, you can see that the current thread name is printed as main while the threads are created using the constructor method call.

Code

package com.tutorialsarena;
class ThreadDemo extends Thread {
ThreadDemo() {
    System.out.println("Thread: " + Thread.currentThread().getName() + ", " + "State: New");
}
public void run() {
    System.out.println("Thread: " + Thread.currentThread().getName() + ", " + "State: Running");
    for (int i = 4; i > 0; i--) {
        System.out.println("Thread: " + Thread.currentThread().getName() + ", " + i); 
    }
    System.out.println("Thread: " + Thread.currentThread().getName() + ", " + "State: Dead");
}
public void start() {
    System.out.println("Thread: " + Thread.currentThread().getName() + ", " + "State: Start");
    super.start();
}
}
public class TestThread {
public static void main(String args[]) {
    ThreadDemo thread1 = new ThreadDemo();
    ThreadDemo thread2 = new ThreadDemo();
    thread1.start();
    thread2.start();
}
}
Output

Thread: main, State: New
Thread: main, State: New
Thread: main, State: Start
Thread: main, State: Start
Thread: Thread-0, State: Running
Thread: Thread-0, 4
Thread: Thread-0, 3
Thread: Thread-1, State: Running
Thread: Thread-1, 4
Thread: Thread-0, 2
Thread: Thread-1, 3
Thread: Thread-0, 1
Thread: Thread-1, 2
Thread: Thread-0, State: Dead
Thread: Thread-1, 1
Thread: Thread-1, State: Dead

Example 2

In this example, we've created a ThreadDemo class that extends the Thread class. Again, we're not passing any name to the thread, which will print the default names assigned by the system. In the main method, we've created two threads. At the end of the main method, we're printing the state of the main thread.

Code

package com.tutorialsarena;
class ThreadDemo extends Thread {
ThreadDemo() {
    System.out.println("Thread: " + Thread.currentThread().getName() + ", " + "State: New");
}
public void run() {
    System.out.println("Thread: " + Thread.currentThread().getName() + ", " + "State: Running");
    for (int i = 4; i > 0; i--) {
        System.out.println("Thread: " + Thread.currentThread().getName() + ", " + i); 
    }
    System.out.println("Thread: " + Thread.currentThread().getName() + ", " + "State: Dead");
}
public void start() {
    System.out.println("Thread: " + Thread.currentThread().getName() + ", " + "State: Start");
    super.start();
}
}
public class TestThread {
public static void main(String args[]) {
    ThreadDemo thread1 = new ThreadDemo();
    ThreadDemo thread2 = new ThreadDemo();
    thread1.start();
    thread2.start();
    System.out.println("Thread: " + Thread.currentThread().getName() + ", " + "State: Dead");
}
}
Output

Thread: main, State: New
Thread: main, State: New
Thread: main, State: Start
Thread: main, State: Start
Thread: Thread-0, State: Running
Thread: main, State: Dead
Thread: Thread-1, State: Running
Thread: Thread-0, 4
Thread: Thread-1, 4
Thread: Thread-1, 3
Thread: Thread-1, 2
Thread: Thread-1, 1
Thread: Thread-1, State: Dead
Thread: Thread-0, 3
Thread: Thread-0, 2
Thread: Thread-0, 1
Thread: Thread-0, State: Dead

In this output, you can observe that the main thread finished its execution earlier while the other threads were still running and completed their execution.