Implementing a Runnable vs Extending a Thread

1. Introduction

“Should I implement a Runnable or extend the Thread class”? is quite a common question.

In this article, we’ll see which approach makes more sense in practice and why.

2. Using Thread

Let’s first define a SimpleThread class that extends Thread:

public class SimpleThread extends Thread {

    private String message;

    // standard logger, constructor

    @Override
    public void run() {
        log.info(message);
    }
}

Let’s also see how we can run a thread of this type:

@Test
public void givenAThread_whenRunIt_thenResult()
  throws Exception {
 
    Thread thread = new SimpleThread(
      "SimpleThread executed using Thread");
    thread.start();
    thread.join();
}

We can also use an ExecutorService to execute the thread:

@Test
public void givenAThread_whenSubmitToES_thenResult()
  throws Exception {
    
    executorService.submit(new SimpleThread(
      "SimpleThread executed using ExecutorService")).get();
}

That’s quite a lot of code for running a single log operation in a separate thread.

Also, note that SimpleThread cannot extend any other class, as Java doesn’t support multiple inheritance.

3. Implementing a Runnable

Now, let’s create a simple task which implements the java.lang.Runnable interface:

class SimpleRunnable implements Runnable {
	
    private String message;
	
    // standard logger, constructor
    
    @Override
    public void run() {
        log.info(message);
    }
}

The above SimpleRunnable is just a task which we want to run in a separate thread.

There’re various approaches we can use for running it; one of them is to use the Thread class:

@Test
public void givenRunnable_whenRunIt_thenResult()
 throws Exception {
    Thread thread = new Thread(new SimpleRunnable(
      "SimpleRunnable executed using Thread"));
    thread.start();
    thread.join();
}

We can even use an ExecutorService:

@Test
public void givenARunnable_whenSubmitToES_thenResult()
 throws Exception {
    
    executorService.submit(new SimpleRunnable(
      "SimpleRunnable executed using ExecutorService")).get();
}

We can read more about ExecutorService in here.

Since we’re now implementing an interface, we’re free to extend another base class if we need to.

Starting with Java 8, any interface which exposes a single abstract method is treated as a functional interface, which makes it a valid lambda expression target.

We can rewrite the above Runnable code using a lambda expression:

@Test
public void givenARunnableLambda_whenSubmitToES_thenResult() 
  throws Exception {
    
    executorService.submit(
      () -> log.info("Lambda runnable executed!"));
}

4. Runnable or Thread?

Simply put, we generally encourage the use of Runnable over Thread:

  • When extending the Thread class, we’re not overriding any of its methods. Instead, we override the method of Runnable (which Thread happens to implement). This is a clear violation of IS-A Thread principle
  • Creating an implementation of Runnable and passing it to the Thread class utilizes composition and not inheritance – which is more flexible
  • After extending the Thread class, we can’t extend any other class
  • From Java 8 onwards, Runnables can be represented as lambda expressions

5. Conclusion

In this quick tutorial, we saw how implementing Runnable is typically a better approach than extending the Thread class.

The code for this post can be found over on GitHub.

Related posts:

Toán tử trong java
Java Program to Find Whether a Path Exists Between 2 Given Nodes
Immutable ArrayList in Java
Java Program to Check Whether Graph is DAG
Java Program to Construct K-D Tree for 2 Dimensional Data
Introduction to Java Serialization
Spring Boot - Creating Docker Image
The DAO with Spring and Hibernate
Tránh lỗi ConcurrentModificationException trong Java như thế nào?
The Difference Between Collection.stream().forEach() and Collection.forEach()
Java Program to Implement Doubly Linked List
Java – Delete a File
Java Program to Solve a Matching Problem for a Given Specific Case
New Features in Java 9
Spring Data JPA Delete and Relationships
The XOR Operator in Java
Java Program to Implement Solovay Strassen Primality Test Algorithm
REST Web service: HTTP Status Code và xử lý ngoại lệ RESTful web service với Jersey 2.x
Câu lệnh điều khiển vòng lặp trong Java (break, continue)
Java Program to Implement Traveling Salesman Problem using Nearest neighbour Algorithm
Spring Boot - Exception Handling
Java Program to Check whether Directed Graph is Connected using BFS
A Custom Data Binder in Spring MVC
The Order of Tests in JUnit
Vấn đề Nhà sản xuất (Producer) – Người tiêu dùng (Consumer) và đồng bộ hóa các luồng trong Java
Logging a Reactive Sequence
Intro to Inversion of Control and Dependency Injection with Spring
Stack Memory and Heap Space in Java
Java Program to Compare Binary and Sequential Search
Guava Collections Cookbook
Java Program to Generate Random Numbers Using Middle Square Method
Java Program to Implement PriorityQueue API