Thread in Java
A Thread is the smallest unit of execution inside a program. It allows Java applications to run multiple tasks at the same time, improving performance, responsiveness, and CPU utilization.
What Is a Thread?
A Thread is a lightweight, independent unit of execution:
- Has its own execution path
- Runs independently
- Shares memory with other threads
- Managed by JVM Thread Scheduler
Java programs start with one main thread, but you can create multiple threads to run tasks concurrently.
Example:
- Thread 1 → Load images
- Thread 2 → Fetch notifications
- Thread 3 → Play music
All tasks run simultaneously.
JVM Thread Scheduler
- Schedules threads based on thread priority + OS scheduling algorithm
- Execution order is unpredictable
- Higher priority threads may not always run first
- Output may vary on each program run
Process vs Thread
Understanding the difference is essential:
Process
- A program in execution
- Has its own memory space
- Heavy & expensive to create
- Does not share data with other processes
Example: Chrome browser, VS Code, IntelliJ
Thread
- A smaller part of a process
- Shares memory with other threads
- Lightweight and fast to create
- Communicates easily with other threads
Example inside Chrome:
- Thread 1 → handles UI
- Thread 2 → loads web pages
- Thread 3 → downloads files
Process vs Thread Comparison Table:
| Feature | Process | Thread |
|---|---|---|
| Definition | Independent program in execution | Lightweight unit of execution inside a process |
| Memory Space | Own separate memory | Shares process memory |
| Communication | Slow, requires IPC | Fast, via shared memory |
| Creation Cost | Heavy | Lightweight |
| Isolation | Fully isolated | Not isolated, shares resources |
| Crash Impact | One process crash does not affect others | One thread crash can affect entire process |
| Execution | Runs independently | Runs inside a process |
| Context Switching | Slow | Fast |
| Resource Usage | High | Low |
| Use Case | Running applications | Multitasking inside an app |
Creating Threads in Java
In Java, threads are created to perform multiple tasks concurrently. There are two main ways to create threads:

1. Extending the Thread Class
You can create a new thread by extending the Thread class and overriding its run() method.
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running...");
}
}
public class Main {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start(); // Start a new thread
}
}
Notes:
- Use
start()to begin the thread, which internally callsrun(). - Avoid calling
run()directly – it executes in the main thread, not a new thread. - Limitation: Java doesn’t support multiple inheritance, so extending
Threadmay not be ideal for large projects.
2. Implementing the Runnable Interface (Recommended)
A more flexible way is to implement the Runnable interface, especially when you want your class to extend another class.
class MyTask implements Runnable {
@Override
public void run() {
System.out.println("Task is running...");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyTask());
thread.start();
}
}
Advantages:
- Supports extending other classes.
- Allows reusing the same task in multiple threads.
- Works seamlessly with the Executor framework.
3. Using Lambda Expressions (Modern & Clean)
With Java 8+, you can create threads using lambda expressions since Runnable is a functional interface.
public class Main {
public static void main(String[] args) {
Thread t = new Thread(() -> System.out.println("Thread running using lambda!"));
t.start();
}
}
Advantages:
- Concise and modern syntax.
- Perfect for small, simple tasks.
4. Using the Executor Framework (Thread Pool)
Instead of manually creating threads, you can use ExecutorService to manage thread pools efficiently.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
Runnable task1 = () -> System.out.println("Task 1 running");
Runnable task2 = () -> System.out.println("Task 2 running");
Runnable task3 = () -> System.out.println("Task 3 running");
executor.submit(task1);
executor.submit(task2);
executor.submit(task3);
executor.shutdown(); // Stop accepting new tasks
}
}
Advantages:
- Manages thread lifecycle automatically.
- Reuses threads, improving performance.
- Ideal for high-concurrency applications.
Complete Thread Example
Thread t1 = new Thread(() -> {
for(int i = 1; i <= 5; i++)
System.out.println("Thread 1: " + i);
});
Thread t2 = new Thread(() -> {
for(int i = 1; i <= 5; i++)
System.out.println("Thread 2: " + i);
});
t1.start();
t2.start();
Output (interleaved):
Thread 1: 1
Thread 2: 1
Thread 1: 2
Thread 2: 2
...
Points to Remember
- A Thread is the smallest unit of execution in Java.
- Java starts with the main thread, and you can create more threads as needed.
- Threads share the same memory, so synchronization is required to avoid issues.
- Thread execution is unpredictable due to the JVM and OS schedulers.
- Always use
start()to run a new thread. - Prefer Runnable or ExecutorService (thread pools) instead of extending
Thread. - Improper synchronization may cause race conditions and deadlocks.
- Use concurrency tools like synchronized, locks, and volatile for thread safety.
- Multithreading improves performance and responsiveness, but too many threads can reduce performance.
