What is Multithreading
Multithreading is a programming technique that allows a single process to run multiple threads concurrently. Threads are smaller, lightweight units of a process that share the same memory and resources. By using multithreading, programs can perform multiple tasks at the same time, making them more efficient and responsive.
Threads within the same process share memory and resources, making them lightweight and efficient for performing tasks in parallel.
Multithreading is useful in below Scenario
Parallel Execution: Multithreading enables different parts of a program to run concurrently, improving performance and responsiveness.
Improving performance : By allowing threads to run concurrently, multithreading can make better use of cpu resources, leading to faster execution of tasks.
Efficient Resource Usage: By sharing the process’s memory and resources, threads are more efficient than creating multiple processes.
Scalability: Multithreading can help applications scale better on multicore processors leveraging the full potential of modern hardware .
Multithreading is particularly useful for taking advantage of multi-core processors, where each thread can run on a separate core.However, it requires careful management to avoid issues like:
Resource contention: When threads compete for limited system resources.
Race conditions: When two or more threads try to modify shared data simultaneously.
Deadlocks: Deadlocks occur when multiple threads become stuck, each waiting for the other to release resources, causing a system halt.
How Thread Will Allocate Memory
In multithreading, threads share the same memory space and resources of the process they belong to. Here’s how memory allocation works for threads:
- Shared Memory: All threads in a process share the same heap memory and global variables. This allows them to communicate and share data efficiently.
- Thread-Specific Memory: Each thread has its own stack memory, used for storing its local variables and function call information. This stack memory is separate for each thread to prevent interference between them.
- Resource Allocation: When a thread is created, the operating system allocates stack memory and essential resources for execution. The stack size is configurable and varies based on the system or programming language.
- Synchronization and Safety: Since threads share heap memory, accessing shared data requires proper synchronization (like mutexes, locks, or semaphores) to avoid race conditions or data corruption.
Thread life cycle
The thread lifecycle in Java describes the various states a thread can go through from its creation to termination.

Thread States
- New:
- A thread is in the created state when it has been initialized but has not started execution.
- Example:
Thread t = new Thread(); - The thread is in the “New” state and hasn’t executed its
run()method yet.
- Runnable:
- When the
start()method is called, the thread enters the “Runnable” state. - The thread is ready to run but waits for CPU time to execute.
- Example:
t.start();
- When the
- Running:
- The thread is actively executing its
run()method. The JVM scheduler selects it for execution. - Note: A thread alternates between “Runnable” and “Running” depending on CPU availability.
- The thread is actively executing its
- Blocked/Waiting/Timed Waiting:
- A thread moves to these states when it waits for resources or another thread’s signal:
- Blocked: Waiting for a resource (e.g., a lock) to become available.
- Waiting: Waiting indefinitely for another thread to signal (using methods like
wait()). - Timed Waiting: Waiting for a specific time (using methods like
sleep()orjoin(timeout)).
- A thread moves to these states when it waits for resources or another thread’s signal:
- Terminated (Dead):
- A thread enters the ‘Terminated’ state when it completes execution or stops due to an exception.
- Example: When the
run()method finishes, the thread is considered “dead.”
How many way we can create thread .
Two way we can create a thread in java using Thread class and Runnable Interface
- Creating Threads Using the
ThreadClass
// Extending the Thread class
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Hello from MyThread: " + Thread.currentThread().getName());
}
}
public class ThreadExample {
public static void main(String[] args) {
// Creating and starting threads
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
thread1.start(); // Start thread1
thread2.start(); // Start thread2
}
}
Key Points:
start()Method: This is used to begin thread execution, invoking therun()method internally.run()Method: Contains the code to be executed by the thread.- Thread Identification:
Thread.currentThread().getName()helps identify the currently executing thread.
Memory Allocation of Above Program
- Heap Memory:
- When
MyThread thread1 = new MyThread();andMyThread thread2 = new MyThread();are executed, two objects of theMyThreadclass are created in the heap memory. - The heap is a shared memory space accessible by all threads. Here, the
MyThreadobjects (instancesthread1andthread2) reside.
- When
- Stack Memory:
- Each thread (
thread1andthread2) has its own stack memory. - The stack is private to each thread and used for storing local variables and method call information.
- When the
run()method executes for each thread, the method’s context (parameters, local variables, and return address) is stored in its respective stack.
- Each thread (
- Shared Resources:
- The code inside the
run()method does not use shared variables; it only prints the thread’s name usingThread.currentThread().getName().
- The code inside the
- Thread-Specific Memory:
- The
Thread.currentThread()object represents the current thread and exists in thread-specific storage. Each thread maintains its own identity and state (such as name, priority, etc.) in this storage.
- The
- Garbage Collection:
- Once
thread1andthread2complete execution, they are eligible for garbage collection since there are no active references to these objects. The JVM automatically handles this cleanup process.
- Once
2.Creating Threads Using the Runnable Interface
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Hello from MyRunnable: " + Thread.currentThread().getName());
}
}
public class RunnableExample {
public static void main(String[] args) {
// Creating and starting threads
Thread thread1 = new Thread(new MyRunnable());
Thread thread2 = new Thread(new MyRunnable());
thread1.start(); // Start thread1
thread2.start(); // Start thread2
}
}
Above code explanation
1. class MyRunnable implements Runnable {
- A new class
MyRunnableis defined, which implements theRunnableinterface. - This means that
MyRunnablemust provide an implementation for therun()method, as required by theRunnableinterface.
2. @Override public void run() {
- The
run()method is overridden in theMyRunnableclass. - When a thread executes, the code inside this
run()method is what gets executed.
3. System.out.println("Hello from MyRunnable: " + Thread.currentThread().getName());
- The
run()method prints a message to the console with the name of the current thread (Thread.currentThread().getName()). Thread.currentThread()retrieves the thread currently executing therun()method.
4. public class RunnableExample {
- The
RunnableExampleclass acts as the entry point for the program. Itsmain()method is where the threads are created and started.
5. Thread thread1 = new Thread(new MyRunnable());
- A new
Threadobject is created, and theMyRunnableinstance is passed as its argument.- Memory Allocation:
- An object of
MyRunnableis created in heap memory. - The
Threadobjectthread1is also created in heap memory.
- An object of
- Memory Allocation:
6. Thread thread2 = new Thread(new MyRunnable());
- Similarly, another
Threadobject is created, with anotherMyRunnableinstance as its argument.- Memory Allocation:
- A second
MyRunnableobject is created in heap memory. - The
Threadobjectthread2is also stored in heap memory.
- A second
- Memory Allocation:
7. thread1.start();
- The
start()method is called onthread1.- This triggers the JVM to execute the
run()method of theMyRunnableinstance associated withthread1. - Memory Allocation:
- A new stack memory is allocated for
thread1. The stack contains local variables and execution context for therun()method.
- A new stack memory is allocated for
- This triggers the JVM to execute the
8. thread2.start();
- Similarly, the
start()method is called onthread2.- This triggers the JVM to execute the
run()method of the secondMyRunnableinstance in a new thread. - Memory Allocation:
- A new stack memory is allocated for
thread2.
- A new stack memory is allocated for
- This triggers the JVM to execute the
Memory Management Overview
- Heap Memory:
- The
MyRunnableinstances (new MyRunnable()) andThreadobjects (new Thread()) are allocated here. - .
- The
- Stack Memory:
- Each thread (
thread1andthread2) gets its own stack memory. - The stack holds:
- Local variables.
- Method call information for the
run()method.
- Each thread (
- Thread-Specific Information:
- Each thread maintains its own state (like priority, name, etc.) in thread-specific memory managed by the JVM.
- Garbage Collection:
- Once
thread1andthread2finish their execution, theMyRunnableobjects andThreadobjects are eligible for garbage collection unless referenced elsewhere.
- Once