JavaRunnable & Thread

Runnable & Thread

The previous page showed threads created by extending Thread directly. The generally preferred pattern instead is implementing the Runnable interface — a functional interface with a single method, run() — and handing an instance of it to a Thread constructor. This separates what work needs doing (the Runnable) from how that work actually gets executed (the Thread).
Implementing Runnable

A class implementing Runnable, run on a Thread

Java
class PrinterTask implements Runnable {
    private final String label;

    PrinterTask(String label) {
        this.label = label;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 3; i++) {
            System.out.println(label + " - step " + i);
        }
    }
}

public class RunnableDemo {
    public static void main(String[] args) {
        Runnable task = new PrinterTask("worker");
        Thread thread = new Thread(task); // hand the Runnable to a Thread
        thread.start();
    }
}
worker - step 1
worker - step 2
worker - step 3
Why This Is the Preferred Pattern
Because PrinterTask only implements an interface rather than extending a class, it remains free to extend some other class if it ever needs to. The Runnable also describes a reusable unit of work independent of any particular Thread — the same Runnable instance could be handed to a thread pool (see the Executors page) instead of a raw Thread, with no changes to the task's code at all.
Lambdas as a Concise Runnable

Since Runnable is a functional interface — exactly one abstract method — a lambda expression can stand in for an entire class definition. This is by far the most common way Runnable shows up in modern Java code.

Before: an explicit Runnable implementation

Java
Runnable verbose = new Runnable() {
    @Override
    public void run() {
        System.out.println("Running in a background thread");
    }
};

new Thread(verbose).start();

After: the same thing as a lambda

Java
Runnable concise = () -> System.out.println("Running in a background thread");
new Thread(concise).start();

// or, skipping the variable entirely:
new Thread(() -> System.out.println("Running in a background thread")).start();
Running in a background thread
Running in a background thread
Note
The lambda syntax for Runnable is covered in more depth on the Functional Interfaces page — the short version is that any interface with a single abstract method can be implemented with a lambda, and Runnable is one of the most commonly used examples of that pattern.

Approach

Extends/implements

Reusable across execution strategies

extends Thread

Extends a concrete class — uses up Java's single-inheritance slot

No — tied to being a Thread

implements Runnable

Implements an interface — class stays free to extend something else

Yes — the same Runnable works with plain Thread or a thread pool

Tip
Default to implements Runnable (often as a lambda) for new code. Reach for extending Thread only in the rare case where you genuinely need to override other Thread behavior beyond run().
  • Implementing Runnable and passing it to new Thread(runnable) is the preferred pattern over extending Thread

  • Runnable separates "what work to do" from "how it gets executed"

  • Runnable is a functional interface, so lambdas can replace a full class or anonymous class

  • A Runnable built this way is portable to other execution strategies like thread pools