Sitemap

Java : Runnable Interface

The Runnable Interface in Java: A Detailed Guide with Examples

--

In Java, multithreading allows programs to perform multiple tasks concurrently. The Runnable interface plays a vital role in Java's thread management system, enabling developers to create and manage threads in a more flexible and efficient way.

In this blog post, we will dive deep into the Runnable interface in Java, its purpose, how to use it, and an example to demonstrate its practical use.

What is the Runnable Interface in Java?

The Runnable interface represents a task that can be executed concurrently by a thread. Unlike extending the Thread class, which limits your class to only inheriting from Thread, implementing Runnable allows your class to implement multiple interfaces. This provides more flexibility and is considered the preferred way to define tasks that need to be executed by multiple threads.

Get Rupam Thakre’s stories in your inbox

Join Medium for free to get updates from this writer.

The Runnable interface has a single method:

public interface Runnable {
void run();
}

The run() method contains the code that should be executed when the thread is started. When a thread is created using the Runnable interface, the run() method will be invoked by the thread when it is started.

Why Use Runnable Over Thread?

  1. Flexibility: By using the Runnable interface, you can still extend other classes (since Java supports single inheritance), while with Thread, you can only extend Thread.
  2. Separation of Concerns: The Runnable interface separates the task (logic) from the thread itself, which makes it easier to maintain and modify.
  3. Better Resource Management: Using the Runnable interface allows you to reuse the same instance of a task in different threads, as opposed to extending Thread, which requires creating a new subclass for each task.

How to Use the Runnable Interface in Java

The Runnable interface is implemented in two simple steps:

  1. Create a class that implements Runnable.
  2. Pass the Runnable object to a Thread.

Here’s how it works in detail:

  1. Create a class that implements the Runnable interface and provides the implementation of the run() method.
  2. Create a Thread object and pass the Runnable instance to it.
  3. Start the thread using the start() method, which internally calls the run() method.

Example 1: Simple Runnable Example

Here’s a basic example that demonstrates how to use the Runnable interface to execute a task in a separate thread.

Code Example:

class MyRunnable implements Runnable {
@Override
public void run() {
// Task to be executed by the thread
System.out.println("Thread is running using Runnable!");
}
public static void main(String[] args) {
// Create a Runnable instance
MyRunnable myRunnable = new MyRunnable();

// Create a Thread and pass the Runnable instance
Thread thread = new Thread(myRunnable);

// Start the thread
thread.start();

System.out.println("Main thread is running!");
}
}

Explanation:

  • The class MyRunnable implements the Runnable interface and overrides the run() method to define the task the thread will perform.
  • We then create a Thread object and pass the MyRunnable instance to it.
  • Calling start() initiates the execution of the run() method in a new thread, and the task is executed concurrently with the main thread.

Output:

Thread is running using Runnable!
Main thread is running!

Note: The order of the output may vary because threads run concurrently.

Example 2: Using Multiple Threads with Runnable

Let’s extend our example to create multiple threads, each executing a task concurrently.

Code Example:

class Task implements Runnable {
private String taskName;
public Task(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
System.out.println("Task " + taskName + " is being executed by " + Thread.currentThread().getName());
}
public static void main(String[] args) {
// Create multiple Runnable tasks
Task task1 = new Task("Task 1");
Task task2 = new Task("Task 2");
Task task3 = new Task("Task 3");
// Create multiple threads
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
Thread thread3 = new Thread(task3);
// Start the threads
thread1.start();
thread2.start();
thread3.start();
}
}

Explanation:

  • We created a class Task that takes a task name as a parameter and prints which task is being executed by which thread.
  • Multiple threads (thread1, thread2, and thread3) are created, each executing a different Task.
  • Each thread will print out its name and the task it is running.

Output:

Task Task 1 is being executed by Thread-0
Task Task 2 is being executed by Thread-1
Task Task 3 is being executed by Thread-2

The output order can vary since the threads run concurrently and the thread scheduler decides which thread runs at any given time.

Using Runnable with ExecutorService

While using the Thread class directly works fine, it’s often more efficient to use ExecutorService to manage thread execution in real-world applications. The ExecutorService manages a pool of threads, improving performance and resource management.

Code Example: Using ExecutorService with Runnable

import java.util.concurrent.*;
class Task implements Runnable {
private String taskName;
public Task(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
System.out.println("Executing " + taskName + " by " + Thread.currentThread().getName());
}
public static void main(String[] args) {
// Create a fixed thread pool with 3 threads
ExecutorService executor = Executors.newFixedThreadPool(3);
// Submit tasks to the executor
executor.submit(new Task("Task 1"));
executor.submit(new Task("Task 2"));
executor.submit(new Task("Task 3"));

// Shutdown the executor
executor.shutdown();
}
}

Explanation:

  • We use the ExecutorService with a fixed thread pool size of 3. This means at most 3 threads will run concurrently.
  • We submit three tasks to the executor, and it assigns them to the available threads in the pool.
  • The shutdown() method is called to clean up resources after the tasks are completed.

Output:

Executing Task 1 by pool-1-thread-1
Executing Task 2 by pool-1-thread-2
Executing Task 3 by pool-1-thread-3

The ExecutorService handles thread creation, task scheduling, and resource management efficiently.

Advantages of Using Runnable

  1. Decouples Task and Thread Management: By using Runnable, you separate the logic (task) from the thread management, making your code more flexible and easier to maintain.
  2. Better Resource Management: You can use ExecutorService to manage a pool of threads, avoiding the overhead of creating new threads each time.
  3. Supports Multiple Threads: A single Runnable instance can be passed to multiple threads, allowing the same task to be executed by different threads concurrently.

Common Use Cases for Runnable

  1. Concurrent Tasks in Applications: When you need to execute multiple tasks concurrently, such as handling requests in a server or processing large data sets in parallel.
  2. UI Thread Handling: In GUI applications (e.g., Swing), Runnable is commonly used to offload long-running tasks to worker threads without blocking the UI.
  3. Background Processes: For background tasks like file I/O or network calls, using Runnable lets you keep the main thread responsive.

Conclusion

The Runnable interface in Java is a powerful tool for creating multithreaded applications. It allows you to define tasks and pass them to threads for concurrent execution, offering a cleaner and more flexible alternative to directly extending the Thread class. Whether you're working with basic threads or using ExecutorService for efficient thread management, the Runnable interface is an essential building block for any Java multithreading application.

By understanding how to implement and utilize the Runnable interface, you can create responsive, efficient, and scalable applications that make full use of modern multi-core processors.

--

--

Rupam Thakre
Rupam Thakre

Written by Rupam Thakre

Java Developer, SpringBoot Developer, Backend Development, Microservices Rest API Development, Angular, Apache Camel, Apache Kafka