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
- Extend Thread class
- Implement Runnable interface
- 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 logicstart()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
Callabletask = () -> 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 ofstart() - 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.
Practical Thread Creation Examples
1. Creating Thread by Extending Thread
class MyThread extends Thread {
public void run() {
System.out.println("Thread using Thread class");
}
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
}
}
2. Creating Thread Using Runnable (Preferred)
class MyTask implements Runnable {
public void run() {
System.out.println("Thread using Runnable");
}
public static void main(String[] args) {
Thread t = new Thread(new MyTask());
t.start();
}
}
3. Thread Using Lambda Expression
class Demo {
public static void main(String[] args) {
Thread t = new Thread(() ->
System.out.println("Thread using Lambda"));
t.start();
}
}
4. Anonymous Runnable Implementation
class Demo {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("Anonymous Runnable");
}
});
t.start();
}
}
5. Multiple Threads Creation
class Demo {
public static void main(String[] args) {
new Thread(() -> System.out.println("Thread 1")).start();
new Thread(() -> System.out.println("Thread 2")).start();
}
}
6. Naming a Thread
class Demo {
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}, "Worker-1");
t.start();
}
}
7. Getting Current Thread
class Demo {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
}
}
Output
main
8. Creating Thread Using ExecutorService (Industry Standard)
import java.util.concurrent.*;
class Demo {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> System.out.println("Executor Thread"));
executor.shutdown();
}
}
9. Fixed Thread Pool
import java.util.concurrent.*;
class Demo {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.execute(() -> System.out.println("Task 1"));
pool.execute(() -> System.out.println("Task 2"));
pool.shutdown();
}
}
10. Creating Thread Using Callable (Returns Value)
import java.util.concurrent.*;
class Demo {
public static void main(String[] args) throws Exception {
Callable task = () -> 10 + 20;
ExecutorService ex = Executors.newSingleThreadExecutor();
Future result = ex.submit(task);
System.out.println(result.get());
ex.shutdown();
}
}
Output
30
11. Difference: run() vs start()
class Demo {
public static void main(String[] args) {
Thread t = new Thread(() -> System.out.println("Thread"));
t.run(); // ❌ no new thread
}
}
Explanation
- run() → normal method
- start() → new thread
12. Thread with Sleep
class Demo {
public static void main(String[] args) {
new Thread(() -> {
try {
Thread.sleep(500);
System.out.println("After sleep");
} catch (Exception e) {}
}).start();
}
}
13. Thread with Join
class Demo {
public static void main(String[] args) throws Exception {
Thread t = new Thread(() -> {
try { Thread.sleep(300); } catch (Exception e) {}
System.out.println("Worker done");
});
t.start();
t.join();
System.out.println("Main resumed");
}
}
14. Daemon Thread Creation
class Demo {
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (true) {}
});
t.setDaemon(true);
t.start();
System.out.println("Main ends");
}
}
15. Thread Priority (Hint to Scheduler)
class Demo {
public static void main(String[] args) {
Thread t = new Thread(() -> System.out.println("Priority"));
t.setPriority(Thread.MAX_PRIORITY);
t.start();
}
}
16. Creating Thread Using Method Reference
class Demo {
static void task() {
System.out.println("Method Reference Thread");
}
public static void main(String[] args) {
Thread t = new Thread(Demo::task);
t.start();
}
}
17. Thread Factory (Advanced)
import java.util.concurrent.*;
class Demo {
public static void main(String[] args) {
ThreadFactory factory = r -> new Thread(r, "Custom-Thread");
ExecutorService ex = Executors.newSingleThreadExecutor(factory);
ex.execute(() -> System.out.println(Thread.currentThread().getName()));
ex.shutdown();
}
}
18. Creating Thread Inside Loop
class Demo {
public static void main(String[] args) {
for (int i = 1; i <= 3; i++) {
int id = i;
new Thread(() -> System.out.println("Thread " + id)).start();
}
}
}
19. Thread with Exception Handling
class Demo {
public static void main(String[] args) {
Thread t = new Thread(() -> {
throw new RuntimeException("Error");
});
t.setUncaughtExceptionHandler(
(th, ex) -> System.out.println("Handled: " + ex.getMessage()));
t.start();
}
}
20. Interview Summary – Creating Threads
- Thread
- Runnable
- Lambda
- ExecutorService
- Callable
Key Points
- Prefer Runnable / ExecutorService
- start() always for new thread
- Callable returns value
- Executor manages threads efficiently
- Daemon threads don’t block JVM exit