Your Success, Our Mission!
6000+ Careers Transformed.
Multithreading is one of Java’s most powerful features that allows concurrent execution of two or more parts of a program — called threads — to maximize CPU utilization. Each thread runs independently, yet shares the same memory space, enabling parallel processing and efficient resource management.
In a single-threaded environment, only one task executes at a time. In contrast, multithreading allows multiple tasks to run simultaneously, improving responsiveness, performance, and throughput.
Threads can be created by either:
The Java Virtual Machine (JVM) manages thread scheduling and execution using a Thread Scheduler based on priorities and system load.
Java’s modern concurrency model (since Java 8+) enhances traditional threads with Executors, Callable, Future, and Virtual Threads (introduced in Java 21), simplifying concurrent programming for scalable applications.
class MyThread extends Thread {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " - Count: " + i);
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start(); // starts first thread
t2.start(); // starts second thread
System.out.println("Main thread completed.");
}
}
Possible Output (interleaved):
Thread-0 - Count: 1
Thread-1 - Count: 1
Thread-0 - Count: 2
Thread-1 - Count: 2
...
Main thread completed.
Explanation:
Two threads (t1 and t2) execute concurrently, printing their counts asynchronously.
The sleep() method pauses each thread briefly, allowing interleaving of execution.
This demonstrates true parallel behavior controlled by the JVM’s thread scheduler.
Component | Description | Example |
Thread | Unit of execution | Thread t = new Thread(); |
Runnable | Interface defining run() | class A implements Runnable |
sleep() | Pauses execution temporarily | Thread.sleep(1000) |
start() | Begins a new thread | t.start(); |
join() | Waits for thread to finish | t.join(); |
The Runnable interface is a functional interface that defines a single method run(). It provides a cleaner, more flexible way to define tasks separate from the thread itself, enabling reuse with different thread pools or executor services.
When a Runnable object is passed to a Thread constructor, the run() method defines what the thread executes. This approach decouples task definition from thread control, which is considered best practice in modern Java design.
A thread in Java follows a lifecycle managed by the JVM:
Developers can control this lifecycle using methods like start(), sleep(), join(), and interrupt().
Understanding thread states is essential for diagnosing concurrency bugs and optimizing performance.
class Task implements Runnable {
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + " executing task...");
try { Thread.sleep(400); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
}
public class RunnableDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Task(), "Worker-1");
Thread thread2 = new Thread(new Task(), "Worker-2");
thread1.start();
thread2.start();
thread1.join(); // Waits for completion
thread2.join();
System.out.println("All tasks completed.");
}
}
Output:
Worker-1 executing task...
Worker-2 executing task...
Worker-1 executing task...
Worker-2 executing task...
All tasks completed.
Explanation:
Each worker thread runs concurrently, performing the same task.
The join() method ensures the main thread waits for both to finish, demonstrating thread coordination and synchronization in execution order.
Thread State | Description | Method / Trigger |
New | Created but not started | new Thread() |
Runnable | Ready for CPU allocation | start() |
Running | Executing code | Scheduler assigns CPU |
Blocked/Waiting | Waiting for lock/resource | wait(), sleep() |
Terminated | Finished execution | Method ends |
In multithreaded applications, multiple threads may try to access shared resources simultaneously, leading to data inconsistency or race conditions.
Java solves this problem using synchronization, which ensures that only one thread accesses a shared resource at a time.
The synchronized keyword can be applied to methods or code blocks to enforce mutual exclusion. This creates a lock on the resource, preventing others from modifying it concurrently.
Java also provides inter-thread communication mechanisms using wait(), notify(), and notifyAll(), allowing threads to coordinate execution by pausing and resuming based on conditions.
Since Java 5+, higher-level concurrency utilities like ReentrantLock, Semaphore, and CountDownLatch in java.util.concurrent offer more flexibility and control.
Synchronization must be used carefully to avoid deadlocks (when two threads wait indefinitely for each other’s locks).
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SyncExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) counter.increment();
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) counter.increment();
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + counter.getCount());
}
}
Output:
Final Count: 2000
Explanation:
Without synchronization, the result would vary due to race conditions.
By marking increment() as synchronized, only one thread at a time can modify count, ensuring data integrity.
Banking systems (avoiding balance inconsistencies).
Inventory management (preventing double updates).
Logging systems (thread-safe file writes).
Thread communication in real-time applications.
Concept | Description | Example |
Synchronization | Mutual exclusion for shared resources | synchronized block |
Inter-thread Communication | Threads signaling each other | wait(), notify() |
Deadlock | Circular lock dependency | Improper nested locks |
ReentrantLock | Advanced lock mechanism | lock.lock() / lock.unlock() |
Top Tutorials
CNN in Deep Learning 2026
A beginner-friendly guide to CNNs: understand deep learning essentials, create Python-based models, and explore advanced applications.
Breaking The Limits: Scaling Databases with MySQL Partitioning
Learn MySQL partitioning with examples. Improve query performance, scalability, and data management using RANGE, LIST, HASH, KEY, and composite techniques.
ML in Action: Hands-On Guide to Deploying and Serving Models
Learn model deployment and serving—from concepts to real-world architectures, tools, APIs, containers, and cloud workflows for production-ready ML.
All Courses (6)
Master's Degree (2)
Fellowship (2)
Certifications (2)