What Are Threads in Java?
In Java, a thread is a lightweight subprocess — the smallest unit of execution. It allows a
program to perform multiple tasks simultaneously, also known as multithreading.
Java provides built-in support for threads via the [Link] class and the Runnable
interface.
Key Concepts
Term Explanation
Thread An independent path of execution in a program.
Multithreading Running two or more threads concurrently.
Main Thread The first thread started when a Java program begins.
Concurrency Ability to execute multiple tasks seemingly at the same time.
Real-World Analogy
Imagine you're cooking while listening to music.
Cooking = one thread
Music = another thread
These tasks are happening simultaneously, much like Java threads.
Java Thread Example
Using Thread Class:
classMyThread extends Thread {
public void run() {
for (inti = 1; i<= 5; i++) {
[Link]("Running Thread: " + i);
}
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
[Link](); // starts a new thread
for (inti = 1; i<= 5; i++) {
[Link]("Main Thread: " + i);
}
}
}
Output (varies per run):
Main Thread: 1
Running Thread: 1
Main Thread: 2
Running Thread: 2
...
Notice: Both threads run independently and their outputs may interleave.
Real-World Use Cases
Scenario Thread Use
Web server handling many clients Each client can be handled by a thread
File downloading while typing Background thread downloads file
Games Separate threads for UI, logic, and audio
Banking software Threads for transactions, alerts, etc.
Life Cycle of a Thread in Java
A thread in Java goes through several stages during its lifetime. These stages make up the
thread life cycle.
Thread Life Cycle States
State Description
New Thread is created but not yet started.
Runnable Thread is ready to run and waiting for CPU time.
Running Thread is currently executing.
Blocked Thread is waiting for a monitor lock (e.g., another thread holds the lock).
Waiting Thread is waiting indefinitely for another thread to perform a task.
Timed Waiting Thread is waiting for a specified time.
Terminated (Dead) Thread has completed execution or has been stopped.
Thread Life Cycle Diagram
Java Example: Thread Lifecycle Demonstration
classDemoThread extends Thread {
public void run() {
[Link]("Thread is running...");
try {
[Link](1000); // Timed waiting state
} catch (InterruptedException e) {
[Link]("Thread interrupted");
}
[Link]("Thread finished.");
}
public static void main(String[] args) {
DemoThread t = new DemoThread(); // New state
[Link]("Thread state after creation: " + [Link]());
[Link](); // Runnable state
[Link]("Thread state after start: " + [Link]());
try {
[Link](200); // Give time for t to enter sleep (timed waiting)
[Link]("Thread state during sleep: " + [Link]());
[Link](); // Wait for thread to die
} catch (InterruptedException e) {
[Link]();
}
[Link]("Thread state after completion: " + [Link]()); //
Terminated
}
}
Output (sample):
Thread state after creation: NEW
Thread state after start: RUNNABLE
Thread is running...
Thread state during sleep: TIMED_WAITING
Thread finished.
Thread state after completion: TERMINATED
In Java, you can create threads using two primary approaches:
1. Extending the Thread class
classMyThread extends Thread {
public void run() {
[Link]("Thread running using Thread class.");
}
public static void main(String[] args) {
MyThread t1 = new MyThread(); // Create thread object
[Link](); // Start thread
}
}
run() contains the code that the thread executes.
start() creates a new thread and calls run() internally.
2. Implementing the Runnable interface
classMyRunnable implements Runnable {
public void run() {
[Link]("Thread running using Runnable interface.");
}
public static void main(String[] args) {
MyRunnablemyRunnable = new MyRunnable();
Thread t1 = new Thread(myRunnable); // Pass runnable to Thread
[Link](); // Start thread
}
}
Recommended when your class extends another class (since Java doesn't support multiple
inheritance).
3. Using Lambda Expression (Java 8+)
public class LambdaThread {
public static void main(String[] args) {
Thread t = new Thread(() -> {
[Link]("Thread running using lambda expression.");
});
[Link]();
}
}
Short and clean for simple tasks.
Comparison
Approach Use When
Extending Thread You don't need to extend another class
Implementing Runnable You want to separate task logic from thread class
Lambda expression You want concise syntax for simple runnable logic
Thread Priorities in Java
In Java, every thread has a priority that helps the Thread Scheduler decide the order in
which threads should be executed.
Priority Range
Constant Value Description
Thread.MIN_PRIORITY 1 Lowest priority
Thread.NORM_PRIORITY 5 Default priority
Thread.MAX_PRIORITY 10 Highest priority
Default priority is 5 (NORM_PRIORITY).
How Priorities Work
Higher-priority threads are more likely to be scheduled before lower-priority threads.
But thread scheduling is JVM and OS dependent – priority is a hint, not a
guarantee.
Example Program
public class ThreadPriorityExample {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
[Link]("Thread 1 running...");
});
Thread t2 = new Thread(() -> {
[Link]("Thread 2 running...");
});
Thread t3 = new Thread(() -> {
[Link]("Thread 3 running...");
});
// Set priorities
[Link](Thread.MIN_PRIORITY); // Priority 1
[Link](Thread.NORM_PRIORITY); // Priority 5
[Link](Thread.MAX_PRIORITY); // Priority 10
// Start threads
[Link]();
[Link]();
[Link]();
}
}
Output (may vary):
Thread 3 running...
Thread 2 running...
Thread 1 running...
Output may differ on different systems, as priority does not enforce strict order.
When to Use Priorities
When some threads are more critical than others (e.g., UI vs background logging).
For fine-tuning performance, but never rely on it for correctness.
Synchronization of Threads in Java
Synchronization in Java is a mechanism to control access to shared resources by multiple
threads. It prevents race conditions, where two or more threads try to modify the same
resource simultaneously.
Why Synchronization is Needed?
If two threads access the same variable or object at the same time, it can lead to data
inconsistency.
How Java Provides Synchronization
Java uses the synchronized keyword to:
Make a method synchronized.
Make a block of code synchronized (within a method).
Example Without Synchronization (Problematic)
class Counter {
int count = 0;
public void increment() {
count++;
}
}
public class UnsynchronizedDemo {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for(inti = 0; i< 1000; i++) [Link]();
});
Thread t2 = new Thread(() -> {
for(inti = 0; i< 1000; i++) [Link]();
});
[Link]();
[Link]();
[Link]();
[Link]();
[Link]("Final count (expected 2000): " + [Link]);
}
}
Output may be less than 2000 because threads overwrite each other.
Example With Synchronization (Corrected)
class Counter {
int count = 0;
public synchronized void increment() {
count++;
}
}
public class SynchronizedDemo {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for(inti = 0; i< 1000; i++) [Link]();
});
Thread t2 = new Thread(() -> {
for(inti = 0; i< 1000; i++) [Link]();
});
[Link]();
[Link]();
[Link]();
[Link]();
[Link]("Final count (expected 2000): " + [Link]);
}
}
Output will always be 2000, thanks to synchronized.
Synchronization Types
Type Usage
Synchronized Method Synchronizes the whole method
Synchronized Block Synchronizes only a critical part
Static Synchronization Synchronizes static methods
Inter-Thread Communication in Java
Inter-thread communication in Java allows multiple threads to communicate and
coordinate with each other using wait-notify mechanisms. It is often used in producer-
consumer problems where threads share a common resource.
Key Methods (Defined in Object class)
Method Description
wait()
Causes the current thread to wait until another thread calls notify() or
notifyAll() on the same object.
notify() Wakes up one thread waiting on the object's monitor.
notifyAll() Wakes up all threads waiting on the object's monitor.
These methods must be called inside a synchronized block or method.
Simple Example: Inter-thread Communication
classSharedResource {
boolean flag = false;
// Producer
synchronized void produce() {
try {
if (flag) wait(); // wait if already produced
[Link]("Producing...");
flag = true;
notify(); // notify consumer
} catch (InterruptedException e) {
[Link]();
}
}
// Consumer
synchronized void consume() {
try {
if (!flag) wait(); // wait if nothing to consume
[Link]("Consuming...");
flag = false;
notify(); // notify producer
} catch (InterruptedException e) {
[Link]();
}
}
}
public class InterThreadExample {
public static void main(String[] args) {
SharedResource res = new SharedResource();
// Producer thread
Thread producer = new Thread(() -> {
for (inti = 0; i< 5; i++) {
[Link]();
}
});
// Consumer thread
Thread consumer = new Thread(() -> {
for (inti = 0; i< 5; i++) {
[Link]();
}
});
[Link]();
[Link]();
}
}
Output:
Producing...
Consuming...
Producing...
Consuming...
...
Important Notes
Always use wait(), notify(), notifyAll() within a synchronized context.
Otherwise, you'll get IllegalMonitorStateException.