Skip to content

Thread Creation in Java

In Java, threads can be created by following two main approaches: extending the Thread class or implementing the Runnable interface. Both approaches allow you to define the task that the thread will perform by overriding the run() method. The choice between these approaches depends on the specific needs of your application.


1. Creating Threads by Extending the Thread Class

The simplest way to create a thread in Java is by extending the Thread class and overriding its run() method. This approach is suitable when your class does not need to inherit from any other class since Java supports single inheritance.

Steps to create a thread using the Thread class:

  • Extend the Thread class.
  • Override the run() method to specify the task the thread should perform.
  • Create an instance of the class and call the start() method to begin execution.

Example:

class MyThread extends Thread {

    public void run() {

        // Task to be executed in the thread

        for (int i = 0; i < 5; i++) {

            System.out.println(“Thread running: ” + i);

        }

    }

}

public class ThreadCreationExample {

    public static void main(String[] args) {

        MyThread thread = new MyThread();

        thread.start(); // Start the thread; this invokes the run method in a new thread of execution

    }

}

Explanation:

  • start() method initiates the thread and calls the run() method in a new thread.
  • The run() method contains the code that will be executed by the thread.

2. Creating Threads by Implementing the Runnable Interface

When you need to create a thread and your class already extends another class (not Thread), implementing the Runnable interface is the better option. This approach is more flexible as it allows your class to inherit from another superclass.

Steps to create a thread using the Runnable interface:

  • Implement the Runnable interface.
  • Override the run() method to specify the task the thread should perform.
  • Create an instance of Thread and pass the Runnable instance to it.
  • Call the start() method on the Thread instance to begin execution.

Example:

class MyRunnable implements Runnable {

    public void run() {

        // Task to be executed in the thread

        for (int i = 0; i < 5; i++) {

            System.out.println(“Runnable thread running: ” + i);

        }

    }

}

public class RunnableExample {

    public static void main(String[] args) {

        MyRunnable myRunnable = new MyRunnable();

        Thread thread = new Thread(myRunnable);

        thread.start(); // Start the thread; this invokes the run method in a new thread of execution

    }

}

Explanation:

  • The Runnable interface has a single method, run(), that defines the code to be executed by the thread.
  • You can create a Thread instance by passing the Runnable object to its constructor.
  • The start() method on the Thread instance is called to initiate the thread and invoke the run() method.

Differences Between Extending Thread and Implementing Runnable

  1. Inheritance:
    1. Thread Class: If you extend Thread, your class cannot extend any other class because Java supports single inheritance.
    1. Runnable Interface: Implementing Runnable allows you to extend another class while still creating threads.
  2. Flexibility:
    1. Thread Class: Suitable for simple scenarios where you don’t need to inherit from other classes.
    1. Runnable Interface: More flexible and follows the principle of composition over inheritance, allowing you to create more modular and maintainable code.
  3. Code Reusability:
    1. Runnable Interface: You can pass the same Runnable instance to multiple Thread objects to execute the same task concurrently.

Thread Creation Best Practices

  • Use Runnable Interface: Prefer using Runnable when you need to implement thread functionality in a class that extends another class, or when you want to execute the same task in multiple threads.
  • Avoid Overriding run() Directly: Do not override the run() method directly unless you extend Thread or implement Runnable.
  • Thread Safety: Be cautious when accessing shared resources between threads to avoid data inconsistency. Use synchronization or concurrent data structures to manage thread safety.

Example of Both Approaches in One Program

Example:

class MyRunnable implements Runnable {

    public void run() {

        System.out.println(“Runnable method running”);

    }

}

public class MultiThreadExample {

    public static void main(String[] args) {

        // Using Thread class

        Thread thread1 = new Thread(() -> System.out.println(“Thread class example”));

        thread1.start();

        // Using Runnable interface

        MyRunnable myRunnable = new MyRunnable();

        Thread thread2 = new Thread(myRunnable);

        thread2.start();

    }

}

Explanation:

  • The first thread (thread1) is created using a lambda expression to demonstrate the simplicity of using a thread without creating a separate class.
  • The second thread (thread2) is created using a Runnable class to show how you can use a custom class with the Runnable interface.

Conclusion

Threads are essential for concurrent programming in Java, making applications more responsive and better at utilizing multi-core processors. Understanding the two main ways to create threads—extending Thread and implementing Runnable—helps in choosing the right approach for your specific use case.