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
Thread
Class
// 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 theMyThread
class are created in the heap memory. - The heap is a shared memory space accessible by all threads. Here, the
MyThread
objects (instancesthread1
andthread2
) reside.
- When
- Stack Memory:
- Each thread (
thread1
andthread2
) 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
thread1
andthread2
complete 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
MyRunnable
is defined, which implements theRunnable
interface. - This means that
MyRunnable
must provide an implementation for therun()
method, as required by theRunnable
interface.
2. @Override public void run() {
- The
run()
method is overridden in theMyRunnable
class. - 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
RunnableExample
class 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
Thread
object is created, and theMyRunnable
instance is passed as its argument.- Memory Allocation:
- An object of
MyRunnable
is created in heap memory. - The
Thread
objectthread1
is also created in heap memory.
- An object of
- Memory Allocation:
6. Thread thread2 = new Thread(new MyRunnable());
- Similarly, another
Thread
object is created, with anotherMyRunnable
instance as its argument.- Memory Allocation:
- A second
MyRunnable
object is created in heap memory. - The
Thread
objectthread2
is 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 theMyRunnable
instance 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 secondMyRunnable
instance 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
MyRunnable
instances (new MyRunnable()
) andThread
objects (new Thread()
) are allocated here. - .
- The
- Stack Memory:
- Each thread (
thread1
andthread2
) 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
thread1
andthread2
finish their execution, theMyRunnable
objects andThread
objects are eligible for garbage collection unless referenced elsewhere.
- Once