In Java, multithreading is one of the core features that allows programs to perform multiple tasks simultaneously. When learning how to create threads, you’ll encounter two commonly used approaches:
- Extending the
Thread
class - Implementing the
Runnable
interface
Both are used to define and execute tasks in separate threads, but they are not the same and serve different design purposes.
In this article, we will explain the difference between Runnable
and Thread
in Java, their advantages and disadvantages, and when to use one over the other — with examples and a clear comparison table.
Introduction to Threading in Java
Multithreading in Java allows multiple parts of a program to execute concurrently, making applications more responsive and efficient — especially for tasks like I/O operations, file processing, or background services.
Java provides two main ways to create threads:
- By extending the
Thread
class - By implementing the
Runnable
interface
Let’s look at both.
What is Thread
in Java?
Thread
is a class in the java.lang
package that represents a single thread of execution. You can create a thread by extending this class and overriding the run()
method.
Example: Using Thread
Class
class MyThread extends Thread {
public void run() {
System.out.println("Thread is running: " + Thread.currentThread().getName());
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); // Starts a new thread
}
}
Output:
Thread is running: Thread-0
Key Points:
- You extend the
Thread
class. - You override the
run()
method to define the thread’s task. - You call
start()
to begin the thread’s execution.
What is Runnable
in Java?
Runnable
is a functional interface in Java that represents a task that can be executed by a thread. Instead of extending Thread
, you implement Runnable
and pass the object to a Thread
instance.
Example: Using Runnable
Interface
class MyTask implements Runnable {
public void run() {
System.out.println("Runnable is running: " + Thread.currentThread().getName());
}
}
public class RunnableExample {
public static void main(String[] args) {
Runnable task = new MyTask();
Thread t1 = new Thread(task);
t1.start(); // Starts a new thread
}
}
Output:
Runnable is running: Thread-0
Key Points:
- You implement the
Runnable
interface. - The thread logic goes inside the
run()
method. - A new
Thread
object is created using theRunnable
object.
📊 Comparison: Runnable
vs Thread

Why Prefer Runnable
Over Thread
?
✅ 1. Java Supports Single Inheritance
Java doesn’t support multiple inheritance. If your class extends Thread
, it cannot extend any other class. But if your class implements Runnable
, it’s free to extend another class too.
class Base {}
class Task extends Base implements Runnable {
public void run() {
System.out.println("Running task...");
}
}
This adds more flexibility and reusability.
✅ 2. Separation of Concerns
When you use Runnable
, the task (business logic) is separated from the thread (execution mechanism). This is a cleaner design because:
- You can reuse the task with different threads.
- You can execute the same task in different ways (e.g., in a thread pool).
✅ 3. Thread Pool Compatibility
Java’s Executor Framework (introduced in Java 5) works with Runnable
, not Thread
.
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(new MyTask()); // MyTask implements Runnable
This is a scalable and efficient way to manage threads — a feature not available with custom Thread
subclasses.
Running Multiple Threads
Let’s see how both approaches run multiple threads:
✅ Using Thread
:
class MyThread extends Thread {
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
}
}
public class TestThread {
public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
}
}
✅ Using Runnable
:
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable running: " + Thread.currentThread().getName());
}
}
public class TestRunnable {
public static void main(String[] args) {
Runnable r = new MyRunnable();
new Thread(r).start();
new Thread(r).start();
}
}
Both methods produce similar output, but the Runnable approach is more scalable and modular.
❌ Common Mistakes to Avoid
1. Calling run()
Instead of start()
Thread t = new Thread(() -> System.out.println("Wrong"));
t.run(); // ❌ Executes in main thread (no multithreading)
✅ Always use start()
to run in a separate thread.
2. Forgetting to Implement run()
in Runnable
class Task implements Runnable {
// Missing run() method – won't compile!
}
✅ Always override the run()
method.
🔁 Summary Table

✅ Final Thoughts
While both Thread
and Runnable
can be used to create and run threads in Java, they serve different purposes:
- Use
Thread
when you have a quick, small task and no need to extend another class. - Use
Runnable
when you want cleaner code, better reusability, and compatibility with executors and thread pools.
Best Practice:
Always prefer implementingRunnable
over extendingThread
in real-world applications.
It gives your code more flexibility, aligns with modern Java concurrency features, and promotes better object-oriented design.
Comments
Post a Comment
Leave Comment