
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: January 8, 2024
“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.
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.
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!"));
}
Simply put, we generally encourage the use of Runnable over Thread:
In this quick tutorial, we saw how implementing Runnable is typically a better approach than extending the Thread class.