Java
Multithreading
Thread
Runnable
Programming Concepts

What's the difference between Thread start and Runnable run

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

In the world of Java concurrency, understanding the difference between Thread's start() method and Runnable's run() method is pivotal for effective multi-threaded application development. Although it may seem subtle, the distinction has significant consequences for how threads are managed and executed.

Understanding the Basics

The Thread Class

Java provides the Thread class, which represents a thread of execution in a program. Thread is a part of the java.lang package and provides developers a way to create concurrent applications with ease.

The Runnable Interface

Runnable is a functional interface, also in the java.lang package. It is designed to provide a common protocol for objects that wish to execute code while they are active. The only method in this interface is run(), which must be defined by any class that implements the interface.

Key Differences Between Thread.start() and Runnable.run()

  1. Invocation:
    • Thread.start(): This method is used to initiate a thread. When invoked, it causes the JVM to call the run() method of the thread in a new call stack, effectively creating a new executing thread.
    • Runnable.run(): This is merely a method call on the current thread; it does not involve any new thread creation. Invoking this method alone executes the run() method in the context of the current thread.
  2. Concurrency:
    • Thread.start(): Concurrency is achieved as start() spawns a new thread that runs the run() method independently.
    • Runnable.run(): No concurrency is achieved. The method simply runs on the already executing thread.
  3. Thread Lifecycle:
    • Thread.start(): Properly manages the thread lifecycle from new (not yet started) to runnable (executing) to terminated (finished execution).
    • Runnable.run(): Does not manage any thread lifecycle as it does not start a separate thread.
  4. Error Handling:
    • Thread.start(): Since it creates a separate thread, any uncaught exceptions are handled by the thread's UncaughtExceptionHandler.
    • Runnable.run(): As it runs on the existing thread, any uncaught exception is propagated up the current call stack.
  5. Call Sequence:
    • Thread.start(): If called more than once on the same Thread instance, it will throw a IllegalThreadStateException.
    • Runnable.run(): Can be called multiple times just like any other method.

Example Scenarios

Using Thread.start()

java
1class MyThread extends Thread {
2    public void run() {
3        System.out.println("Thread is running separately.");
4    }
5}
6
7public class TestThread {
8    public static void main(String[] args) {
9        MyThread t1 = new MyThread();
10        t1.start(); // This will create a new thread and run the `run` method separately.
11    }
12}

Using Runnable.run()

java
1class MyRunnable implements Runnable {
2    public void run() {
3        System.out.println("Run method is executed on the current thread.");
4    }
5}
6
7public class TestRunnable {
8    public static void main(String[] args) {
9        MyRunnable r1 = new MyRunnable();
10        r1.run(); // This will execute the `run` method on the main thread.
11    }
12}

Comparison Overview

Below is a table summarizing the differences:

FeatureThread.start()Runnable.run()
InvocationStarts a new threadInvokes a method on the current thread
ConcurrencyAchieves concurrencyNo concurrency
Thread LifecycleManages lifecycle from new -> runnable -> terminatedNo lifecycle management
Error HandlingHandled by UncaughtExceptionHandlerPropagated up the current call stack
Call SequenceThrows IllegalThreadStateException if called multiple times on same instanceCan be called multiple times without issue

Additional Considerations

Performance Implications

Using Thread.start() involves more overhead due to the creation and management of a new thread. While modern JVMs efficiently handle threads, excessive thread creation can impact performance. On the other hand, invoking run() has no threading overhead but will not leverage the benefits of multi-core processors.

Best Practices

  1. Prefer Implementing Runnable: It is generally recommended to implement Runnable rather than extending Thread. This promotes better object-oriented design, as Java supports single inheritance and using Runnable allows for more flexible class hierarchies.
  2. Use Executors for Complex Applications: For applications requiring extensive multithreading, consider utilizing the java.util.concurrent.Executor framework. It manages thread creation and provides a more comprehensive set of features.

Understanding these differences will aid in making informed decisions when designing concurrent Java applications, ensuring both efficiency and reliability in execution.


Course illustration
Course illustration

All Rights Reserved.