← Back to Home

Creating Threads

In Java, threads enable concurrent execution within a single process. Java provides two primary ways to create threads, plus modern executor-based approaches used in production systems. This is a high-frequency interview topic.

Ways to Create Threads in Java

  1. Extend Thread class
  2. Implement Runnable interface
  3. Implement Callable (Executor framework) (advanced/modern)

1️⃣ Creating a Thread by Extending Thread Class

How It Works

  • Create a subclass of Thread
  • Override the run() method
  • Call start() to begin execution

Example

class MyThread extends Thread {

@Override
    public void run() {
        System.out.println("Thread running: " + Thread.currentThread().getName());
    }
}

public class Test {
    public static void main(String[] args) {
        MyThread t = new MyThread();
        t.start(); // starts new thread
    }
}
          

Important Rules

  • run() contains the thread logic
  • start() creates a new call stack
  • Calling run() directly ❌ does NOT create a new thread

Limitations

  • Java does not support multiple inheritance
  • Class cannot extend any other class

2️⃣ Creating a Thread by Implementing Runnable (Most Preferred)

How It Works

  • Implement Runnable
  • Pass object to Thread constructor
  • Call start()

Example

class MyTask implements Runnable {

@Override
    public void run() {
        System.out.println("Thread running: " + Thread.currentThread().getName());
    }
}

public class Test {
    public static void main(String[] args) {
        Thread t = new Thread(new MyTask());
        t.start();
    }
}
          

Why Runnable Is Preferred (Interview Point)

  • Supports multiple inheritance
  • Separates task from thread
  • Better object-oriented design
  • Widely used in frameworks

3️⃣ Creating Thread Using Lambda (Java 8+)

Thread t = new Thread(() -> {
    System.out.println("Thread using lambda");
});
t.start();
          
  • ✔ Clean
  • ✔ Modern
  • ✔ Uses Runnable internally

4️⃣ Creating Threads Using Callable (Executor Framework)

Used when:

  • Thread must return a value
  • Thread may throw checked exceptions
Callable task = () -> 10 + 20;

ExecutorService service = Executors.newSingleThreadExecutor();
Future result = service.submit(task);

System.out.println(result.get());
service.shutdown();
          
  • ✔ Production-ready
  • ✔ Controlled thread management

start() vs run() (Very Important)

Method Behavior
start() Creates new thread
run() Executes like normal method
t.run();   // ❌ no new thread
t.start(); // ✔ new thread
          

Thread Naming (Good Practice)

Thread t = new Thread(new MyTask(), "Worker-1");
t.start();
          

Thread Priority (Hint)

t.setPriority(Thread.MAX_PRIORITY);
          

⚠ Priority is scheduler-dependent

Comparison: Thread vs Runnable (Interview Favorite)

Aspect Thread Runnable
Inheritance Extends Thread Implements Runnable
Multiple inheritance ❌ No ✔ Yes
Code separation ❌ Poor ✔ Good
Recommended ❌ Less ✔ More

Best Practices (Real-World)

  • Prefer Runnable / Callable over extending Thread
  • Use ExecutorService for thread management
  • Avoid manual thread creation in large systems
  • Name threads meaningfully
  • Do not override start()

Common Beginner Mistakes

  • Calling run() instead of start()
  • Extending Thread unnecessarily
  • Creating too many threads
  • Ignoring thread lifecycle
  • Not shutting down executors

Interview-Ready Answers

Short Answer

Threads can be created by extending the Thread class or implementing Runnable.

Detailed Answer

In Java, threads can be created by extending the Thread class or implementing the Runnable interface. Implementing Runnable is preferred because it supports multiple inheritance and separates task logic from thread management. Modern applications use the Executor framework with Runnable or Callable for better scalability.

Key Takeaway

Runnable for design.
Thread for execution.
Executor for production.
Mastering thread creation is the foundation for safe, scalable, and efficient Java concurrency.