We can define, instantiate and starting a thread by using the following 2 ways.

  1. By extending Thread class.
  2. By implementing Runnable interface.

By extending Thread Class

//Definig a thread
class MyThread extends Thread{
	
	public void run(){
		//job of a thread
		for(int i=0;i<=10;i++){
			System.out.println("Child Thread");
			
		}
		
	}
	
}
public class ThreadDemo {

	public static void main(String[] args) {
		//Instantiating a thread
		MyThread t=new MyThread();
		//Starting a thread
		t.start();
		for(int i=0;i<=10;i++){
			System.out.println("Main Thread");
		}
	}
}
/*
Possible Outputs:
Main Thread     Child Thread        Main Thread     Child Thread
Main Thread     Child Thread        Child Thread    Main Thread
Main Thread     Child Thread        Main Thread     Child Thread
.                .                  Child Thread    Main Thread
.                .                   .               .
Child Thread    Main Thread          .               .
Child Thread    Main Thread
Child Thread    Main Thread
.                    .
.                    .
*/

Thread Scheduler:

  1. If multiple threads are present,then which thread will get chance first for execution will be decided by “Thread Scheduler”.
  2. The behavior of the Thread scheduler is vendor dependent and hence we can’t expect exact output for the above program.

Case:1 Difference between t.start() and t.run() method.

  1. In the case of t.start() method,a new thread will be created and which is responsible for the execution of run method.
  2. But in the case of t.run() method, No new thread will be created and run() method will be executed just like a normal method call.
  3. In the above program,If we replace t.start() with t.run() the following is the output.
    Child Thread
    Child Thread

    Main Thread
    Main Thread
    ..

Case:2 Specialty of Thread class t.start() method.

The start() method available in Thread class is responsible to register out thread with Thread Schedular.Hence without executing thread class start() method,there is no chance of starting the new thread.

start(){
   //1.Register out Thread with Thread Scheduler.
   //2.Invoking run() method.
}

Case:3 If we are not overriding run() method.

If we are not overriding run() method,Thread class run method will be executed which has empty implementation,hence we won’t get any output.

class MyThread extends Thread{
	
			
}
public class ThreadDemo {

	public static void main(String[] args) {
		//Instantiating a thread
		MyThread t=new MyThread();
		//Starting a thread
		t.start();

	}
}
/*
Output:
No output.
*/

Case:4 If we are overriding start() method.

If we are overriding start() method,then our start() method will be executed just like a normal method call and no new thread will be created.

class MyThread extends Thread{
   public void start(){
    System.out.println("start method");
   }
   public void run(){
     System.out.println("run method");
   }
			
}
public class ThreadDemo {

	public static void main(String[] args) {
		//Instantiating a thread
		MyThread t=new MyThread();
		//Starting a thread
		t.start();
        System.out.println("main method");


	}
}
/*
Output:
start method
main method
*/

Note: It is not recommended to override start() method but highly recommended to override run() method.

By Implementing Runnable Interface

We can define a Thread by implementing Runnable interface also. Runnable interface available in java.lang package and contains only one method. i.e. public void run()

Example:

class TestRunnable implements Runnable{
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println("Child thread");
        }
    }
}
public class ThreadDemo {
 
    public static void main(String[] args) {
         
        TestRunnable testRunnable = new TestRunnable();
        Thread thread=new Thread(testRunnable);
        thread.start();
        for (int i = 1; i <= 10; i++) {
            System.out.println("Main thread");
        }
    }
}
/*
Possible Outputs:
Main Thread     Child Thread        Main Thread     Child Thread
Main Thread     Child Thread        Child Thread    Main Thread
Main Thread     Child Thread        Main Thread     Child Thread
.                .                  Child Thread    Main Thread
.                .                   .               .
Child Thread    Main Thread          .               .
Child Thread    Main Thread
Child Thread    Main Thread
.                    .
.                    .
*/ 

Note: Among two approaches of defining a thread implements Runnable approach is always recommended to use.
In the first approach,our class is already extending a Thread class,hence there is no chance of extending any other class. i.e. we are missing inheritance benifits.