Threading in Java
Threading is a technique in Java to allow multiple tasks to run concurrently (in parallel or in interleaved fashion).
A thread is a lightweight sub-process — the smallest unit of execution.
✅ Java provides built-in support for multithreading via the
java.lang.Thread
class and theRunnable
interface.
🔄 Why Use Threads?
- Improve performance via parallel execution
- Perform background tasks (e.g., file download, animations)
- Efficient use of CPU resources
🧩 Ways to Create a Thread
1. By Extending Thread
Class
2. By Implementing Runnable
Interface
⏱️ Thread Lifecycle
🔧 Common Thread Methods
Method | Description |
---|---|
start() |
Starts the thread |
run() |
Code to execute in thread |
sleep(ms) |
Pauses the thread |
join() |
Waits for thread to finish |
isAlive() |
Checks if thread is still running |
setPriority() |
Sets thread priority (1 to 10) |
public class Demo extends Thread {
public void run() {
for (int i = 1; i <= 3; i++) {
System.out.println(i);
try { Thread.sleep(1000); } catch (Exception e) {}
}
}
public static void main(String[] args) throws InterruptedException {
Demo t1 = new Demo();
Demo t2 = new Demo();
t1.start();
t1.join(); // wait for t1 to finish
t2.start();
}
}
🧠 Example with sleep()
and join()
:
⚠️ Thread Safety & Concurrency
- Multiple threads accessing shared data can cause race conditions
- Use synchronization (
synchronized
keyword), locks, or concurrent APIs (ReentrantLock
,AtomicInteger
, etc.)
✅ Summary
Feature | Description |
---|---|
Thread | Lightweight process |
Concurrency | Multiple threads executing in parallel |
Thread class | Built-in support for creating threads |
Runnable | Preferred approach (decouples logic) |
Use cases | Background tasks, async processing |
🧵 What is a Thread Pool?
A Thread Pool is a collection of pre-instantiated reusable threads managed by the Java runtime to execute multiple tasks efficiently.
✅ Instead of creating a new thread every time, Java reuses existing threads from the pool → improves performance, scalability, and resource management.
📦 Part of:
java.util.concurrent
package
✅ Why Use a Thread Pool?
- Reduces overhead of thread creation
- Limits number of concurrent threads
- Avoids resource exhaustion
- Ideal for handling large numbers of short tasks
🔧 Creating a Thread Pool
Java provides the Executors
utility class to create thread pools.
🛠️ Types of Thread Pools in Java:
Method | Description |
---|---|
newFixedThreadPool(int n) |
Pool with fixed number of threads |
newCachedThreadPool() |
Creates new threads as needed; reuses old ones |
newSingleThreadExecutor() |
Only one thread executes tasks sequentially |
newScheduledThreadPool(int n) |
Executes tasks with delay or periodically |
🧠 Important Interfaces:
-
ExecutorService
– interface to manage and control thread pool execution. -
Key methods:
execute(Runnable r)
-
submit(Callable<T> c)
– returns result (Future
) -
shutdown()
– graceful shutdown -
shutdownNow()
– force shutdown -
awaitTermination()
– wait until all tasks complete
⚠️ Best Practices:
- Always call
shutdown()
after use - Use
submit()
instead ofexecute()
if return value is needed - Avoid using more threads than available CPU cores unless tasks are I/O bound
✅ Summary:
Feature | Description |
---|---|
Purpose | Reuse threads for efficient task execution |
Key API |
Executors , ExecutorService
|
Types | Fixed, Cached, Single, Scheduled |
Use cases | Web servers, batch processing, task queues |
🧵 Callable and Future in Java Threading
In Java, Callable
and Future
are used to perform concurrent tasks that return a result or throw exceptions, unlike Runnable
, which does neither.
🔄 1. Callable Interface
Callable<V>
is a functional interface that:
- Returns a result
- Can throw checked exceptions
📦 Package: java.util.concurrent
🧪 Syntax:
⏳ 2. Future Interface
Future<V>
represents the result of an asynchronous computation.
You get a Future
object when you submit a Callable
to an executor.
You can use it to:
- Check if the task is done
- Cancel the task
- Retrieve the result
🔧 Example with ExecutorService
🧾 Output:
🆚 Callable vs Runnable
Feature | Runnable |
Callable<V> |
---|---|---|
Returns value | ❌ No | ✅ Yes (V ) |
Throws checked exceptions | ❌ No | ✅ Yes |
Used with |
Thread , ExecutorService
|
ExecutorService |
✅ Summary
Interface | Purpose | Key Method |
---|---|---|
Callable<V> |
Task that returns a result | V call() |
Future<V> |
Handle async result | V get(), cancel() |
⏰ What is Thread Scheduling in Java?
Scheduling threads means executing tasks:
- After a delay
- At fixed intervals (repeatedly)
Java provides the ScheduledExecutorService
for scheduled and periodic task execution, replacing older Timer
and TimerTask
classes.
📦 Package:
java.util.concurrent
✅ Key Interface: ScheduledExecutorService
You can get it via:
🔧 Common Scheduling Methods:
Method | Description |
---|---|
schedule(Runnable task, delay, unit) |
Runs once after a delay |
scheduleAtFixedRate(task, initDelay, period, unit) |
Repeats at fixed intervals, regardless of task duration |
scheduleWithFixedDelay(task, initDelay, delay, unit) |
Waits for task to finish, then waits again before restarting |
🧪 Example: One-Time Delayed Task
import java.util.concurrent.*;
public class DelayedTaskExample {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable task = () -> System.out.println("Executed after 3 seconds");
scheduler.schedule(task, 3, TimeUnit.SECONDS);
scheduler.shutdown();
}
}
🧪 Example: Repeating Task (Fixed Rate)
🕒 Starts after 1 second, then repeats every 2 seconds (regardless of how long the task takes).
🧪 Example: Repeating Task (Fixed Delay)
🕒 Starts after 1 second, then waits 2 seconds after task completes before running again.
⚠️ Tips:
- Use
shutdown()
to stop gracefully - Use
scheduleWithFixedDelay
for variable-length tasks - Use
scheduleAtFixedRate
for time-sensitive periodic tasks
✅ Summary:
Feature | ScheduledExecutorService |
---|---|
One-time delay | schedule() |
Repeating task |
scheduleAtFixedRate() , scheduleWithFixedDelay()
|
Thread-safe? | ✅ Yes |
Replacement for |
Timer and TimerTask
|
👻 What is a Daemon Thread?
A Daemon Thread in Java is a background thread that runs in support of user (non-daemon) threads.
It automatically terminates when all user threads have finished execution.
✅ Think of it like a helper thread (e.g., garbage collector, background logging).
✅ Key Characteristics:
Feature | Description |
---|---|
Purpose | Run background tasks |
Lifetime | Ends automatically when all user threads are done |
Priority | Usually low |
Use cases | GC, monitoring, background cleanup, scheduler |
Converts to daemon | Only before starting (setDaemon(true) must be called before start() ) |
🔧 How to Create a Daemon Thread
🔹 Example:
🔍 Output:
You may see the daemon output once or twice, but it will stop as soon as the main thread ends.
⚠️ Rules:
- Must call
setDaemon(true)
before starting the thread - Daemon threads should not perform critical tasks
- You cannot make the main thread a daemon
🧠 Daemon vs User Thread:
Property | User Thread | Daemon Thread |
---|---|---|
Execution ends? | When run() completes |
When all user threads finish |
Used for? | Core business logic | Background services |
JVM waits to finish? | ✅ Yes | ❌ No (terminates automatically) |
Created by default? | ✅ Main thread is user | ❌ Must be explicitly set |
✅ Summary:
- Daemon = background helper
- Stops when no more user threads are running
- Use for non-critical background work
- Set with
setDaemon(true)
beforestart()
🎚️ What is Thread Priority?
In Java, thread priority helps the scheduler decide which thread to execute first when multiple threads are ready to run.
Each thread is assigned a priority between 1 (MIN_PRIORITY) and 10 (MAX_PRIORITY).
💡 Higher-priority threads are more likely to be selected for execution, but it's not guaranteed (depends on JVM & OS).
✅ Priority Constants (from Thread
class):
Constant | Value | Description |
---|---|---|
Thread.MIN_PRIORITY |
1 | Lowest priority |
Thread.NORM_PRIORITY |
5 | Default priority |
Thread.MAX_PRIORITY |
10 | Highest priority |
🔧 How to Set/Get Priority:
🧪 Example:
⚠️ Important Notes:
- Priority affects scheduling, not correctness.
- JVM thread scheduler behavior can vary across platforms.
- Threads with higher priority may not always run first.
📌 Summary:
Feature | Value |
---|---|
Range | 1 to 10 |
Default | 5 (NORM_PRIORITY ) |
Effect | Hints scheduler, no guarantee |
Use-case | When some threads are more important (e.g., UI vs background work) |
👥 What is ThreadGroup
in Java?
The ThreadGroup
class is used to group multiple threads into a single unit.
This allows you to manage a group of threads together — like checking their status, interrupting them all at once, etc.
✅ Useful for organizing related threads and performing batch operations on them.
📦 Package:
java.lang.ThreadGroup
✅ Key Features:
Feature | Description |
---|---|
Thread grouping | You can manage multiple threads as a group |
Hierarchy supported | A ThreadGroup can have a parent group
|
Priority control | You can set max priority for all threads in the group |
Interrupt control | You can interrupt all threads in the group at once |
Thread management | View count, enumerate active threads, etc. |
🔧 Common Constructors:
🧪 Example:
🧰 Useful Methods:
Method | Description |
---|---|
activeCount() |
Number of active threads |
enumerate(Thread[] tArray) |
Copies threads into an array |
interrupt() |
Interrupts all threads in the group |
getName() |
Returns name of the group |
getParent() |
Returns parent group |
setMaxPriority(int priority) |
Sets max priority for new threads |
⚠️ Limitations:
- Rarely used in modern Java.
- Thread management is better handled via Executors/ThreadPool in
java.util.concurrent
.
✅ Summary:
Feature | Description |
---|---|
Class Name | ThreadGroup |
Purpose | Group and manage multiple threads |
Hierarchical? | ✅ Supports parent-child structure |
Modern use? | ⚠️ Rare – replaced by Executor framework |