Threads vs Runnable

When working with multithreading in Java, two essential concepts that you’ll often come across are Threads and Runnable. While they are closely related, they serve different purposes in the Java concurrency model.

Feature Thread Runnable
Type Thread is a class. Runnable is an interface.
Inheritance Thread extends the Thread class. This means that if you use Thread, your class cannot inherit from another class. Runnable is an interface, which means it can be implemented by any class, allowing for multiple inheritance (you can implement Runnable in a class that extends another class).
Task Definition The task is defined by overriding the run() method in a Thread class. The task is defined by implementing the run() method in a Runnable interface.
Multiple Inheritance A class that extends Thread can only extend one class, as Java supports single inheritance. A class can implement multiple interfaces, so you can implement Runnable along with other interfaces in your class.
Thread Creation To create a thread, you directly create an instance of the Thread class and override its run() method. Example: Thread thread = new Thread(); thread.start(); To create a thread, you create an instance of a class that implements Runnable and pass it to a Thread object. Example: Runnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start();
Flexibility Less flexible. Since Thread is a class, you cannot inherit from another class while extending Thread. More flexible. Since Runnable is an interface, you can implement it in any class, even if that class already extends another class.
Use in Executor Framework Typically not used directly in Java’s Executor Framework. The thread management is handled manually. Runnable is commonly used with the Executor Framework, such as ExecutorService, because it separates task definition from thread management.
Resource Management Threads created using the Thread class are managed directly by the developer. This can lead to more complex resource management, like managing thread pools manually. Runnable can be used in conjunction with thread pools (via ExecutorService), which automatically manages resource allocation and thread reuse, leading to more efficient resource usage.
Code Reusability Less reusable. If you extend Thread, the task is tightly bound to the thread creation process, limiting its reusability. Highly reusable. Since Runnable defines only the task logic, you can pass the same Runnable instance to multiple threads for concurrent execution.
Control Over Thread Behavior Allows direct control over the thread’s behavior, such as its priority, daemon status, and interrupt handling. Does not directly control thread behavior. You must use it with a Thread object or thread pool to control the thread’s characteristics.
Example Code