Skip to main content

Creating Threads in Java

There are two primary ways to create a thread in Java:

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

Both methods have their use cases, but implementing the Runnable interface is generally preferred.


1. By Extending the Thread Class

To create a thread using the Thread class, you need to:

  1. Create a class that extends the java.lang.Thread class.
  2. Override the run() method. This method contains the code that will be executed by the thread.
  3. Create an object of your class and call the start() method to begin execution.

Example: Extending Thread

class LabThread1 extends Thread {

// Overriding the run method
public void run() {
System.out.println("Thread is running via Thread class!");
}

public static void main(String args[]) {
// Creating an object of our custom thread class
LabThread1 t1 = new LabThread1();

// Calling start() to spawn the thread and execute run()
t1.start();
}
}

[!WARNING] Never call the run() method directly. Calling run() directly will execute the code sequentially in the current thread (the main thread) rather than spawning a new thread. Always use start().


2. By Implementing the Runnable Interface

To create a thread using the Runnable interface, you need to:

  1. Create a class that implements the java.lang.Runnable interface.
  2. Provide the implementation for the run() method.
  3. Pass an instance of your class to a Thread object's constructor.
  4. Call the start() method on the Thread object.

Example: Implementing Runnable

class LabThread2 implements Runnable {

// Providing implementation for the run method
public void run() {
System.out.println("Thread is running via Runnable interface!");
}

public static void main(String args[]) {
// 1. Create an instance of the class
LabThread2 m1 = new LabThread2();

// 2. Pass it to a Thread object
Thread t1 = new Thread(m1);

// 3. Call start()
t1.start();
}
}

Which approach is better?

Implementing the Runnable interface is generally considered the better approach for the following reasons:

FeatureExtending Thread ClassImplementing Runnable Interface
Multiple InheritanceJava does not support multiple inheritance. If you extend Thread, your class cannot extend any other class.Since Runnable is an interface, your class can implement Runnable and still extend another class.
Object OrientationExtending Thread means your class is a Thread, which may not be logically accurate if your class just needs to run some task.Implementing Runnable separates the task (the run method) from the runner (the Thread), adhering better to OOP principles.
Resource SharingHarder to share resources across multiple threads.Easier to share resources because you can pass the same Runnable instance to multiple Thread objects.

[!TIP] From Java 8 onwards, because Runnable is a Functional Interface (it has only one abstract method, run()), you can create and start threads elegantly using Lambda Expressions:

public class LabThread3 {

public static void main(String args[]) {
// Using Lambda Expression for Runnable
Thread t1 = new Thread(() -> {
System.out.println("Thread is running via Lambda Expression!");
});

t1.start();
}
}