0% found this document useful (0 votes)
2 views14 pages

Multithreading in Java

A thread is a path of execution within a program, allowing multiple tasks to run concurrently, improving performance and responsiveness. Java provides various methods for creating and managing threads, including extending the Thread class or implementing the Runnable interface, and it also defines a lifecycle for threads with states like New, Runnable, and Terminated. Synchronization is crucial to prevent data inconsistency when multiple threads access shared resources, and deadlocks can occur when threads wait indefinitely for each other, which can be avoided through strategies like lock ordering and using higher-level concurrency APIs.

Uploaded by

suhasthorat30
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views14 pages

Multithreading in Java

A thread is a path of execution within a program, allowing multiple tasks to run concurrently, improving performance and responsiveness. Java provides various methods for creating and managing threads, including extending the Thread class or implementing the Runnable interface, and it also defines a lifecycle for threads with states like New, Runnable, and Terminated. Synchronization is crucial to prevent data inconsistency when multiple threads access shared resources, and deadlocks can occur when threads wait indefinitely for each other, which can be avoided through strategies like lock ordering and using higher-level concurrency APIs.

Uploaded by

suhasthorat30
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

What is a Thread?

A thread is a path of execution within a program.


In simple words: A program has at least one thread (called the main thread), and you can create more to do multiple things
at once.

Real-life analogy:
Imagine you're cooking food while listening to music and downloading a file in the background these are multiple tasks
happening in parallel, just like threads in a program.

Why Use Threads?

Threads help you:

Do things in parallel (like downloading a file while showing a progress bar)


Improve performance for I/O-heavy or waiting tasks
Make apps more responsive (e.g., UIs)

How to Create a Thread

There are two common ways to create a thread in Java.

a) Extending the Thread class

run() method contains the code you want to run in the new thread.
start() actually starts the thread and calls run() behind the scenes.

b) Implementing the Runnable interface


This is better practice because Java supports single inheritance. If you extend Thread, you can't extend any other class.

What is the Thread Lifecycle?

A thread goes through below states:

State Meaning

New Thread is created but not started yet.

Runnable Thread is ready and waiting for CPU.

Running Thread is currently executing.

Blocked Thread is waiting for a lock/monitor.

Waiting Thread is waiting indefinitely for another thread.

Timed Waiting Thread waits for a specific time (e.g., sleep, join(timeout))

Terminated Thread has completed execution or exited due to an


exception.

List of Useful Java Thread Methods

1. start()
What it does: Starts a new thread and calls the run() method in the background.

2. run()

What it does: Defines the code that should run in the thread.
Note: You should not call run() directly use start() instead.

3. sleep(long milliseconds)

What it does: Puts the current thread to sleep for the given time (in ms).

Useful when simulating a delay.

4. join()

What it does: Makes one thread wait for another to finish.

5. isAlive()

What it does: Returns true if the thread is still running.

6. getName() / setName(String)

What it does: Gets or sets the name of the thread.


7. getId()

What it does: Returns the unique ID of a thread.

8. getPriority() / setPriority(int)

What it does: Gets or sets the priority of a thread (1 to 10).

Note: Thread priority is just a hint to the OS scheduler, not a guarantee.

MIN_PRIORITY = 1
NORM_PRIORITY = 5
MAX_PRIORITY = 10

9. isDaemon() / setDaemon(boolean)

What it does: A daemon thread runs in the background (e.g., garbage collection) and doesn't block JVM shutdown.

You must call setDaemon(true) before calling start().

10. interrupt()

What it does: Interrupts a thread usually used to signal a thread to stop.


11. isInterrupted()

What it does: Checks whether the thread has been interrupted.

12. currentThread()

What it does: Returns the currently running thread.

Very useful for debugging or naming log output.

13. yield()

What it does: Suggests the currently executing thread to pause and allow other threads of equal priority to execute.

Note: It's just a hint, not a guarantee. Often used in tight CPU loops to be polite.

Summary:
Method Use Case

start() Begin thread execution

run() Define the thread task

sleep() Pause execution

join() Wait for another thread

isAlive() Check if thread is still running

get/setName() Identify threads

getId() Unique ID for thread

get/setPriority() Set execution preference

setDaemon() Mark as background thread

interrupt() Ask thread to stop

isInterrupted() Check if thread is interrupted

currentThread() Get current thread reference

yield() Pause to give chance to others

Thread Example – Download + Loading Animation


This simulates:

A file downloading (Thread 1)


A loading animation shown during download (Thread 2)

JVM Thread Scheduler: The Real Picture

1. JVM Does Not Have Its Own Scheduler

The Java Virtual Machine (JVM):

Creates and manages threads using Java APIs (Thread, Runnable, etc.)
Keeps track of thread state, metadata, stack memory, and locks
But does not control actual CPU execution time
Instead, it relies entirely on the OS thread scheduler

JVM ≠ Thread scheduler


JVM = Thread manager + lifecycle tracker

2. OS Thread Scheduling: The Real Scheduler

The OS uses a thread scheduler algorithm. Java threads are mapped 1:1 with native OS threads using system calls like:

pthread_create() on Unix/Linux
CreateThread() on Windows

3. Types of Scheduling Used by OS (and leveraged by JVM)

The actual scheduling algorithm depends on the OS. JVM threads benefit from these algorithms.

A. Preemptive Scheduling

Every thread gets a small time slice (quantum)


OS forcibly switches to another thread when the time is up
Used by almost all modern OS schedulers
Ensures fairness and avoids starvation
B. Priority-Based Scheduling

Threads have priorities (Java: 1 to 10)


Higher priority threads get more CPU time (if the OS respects it)
May lead to starvation of lower-priority threads

4. Common OS Scheduling Algorithms Used

OS Scheduling Algorithm Java Thread Support

Linux Completely Fair Scheduler (CFS) YES

Windows Multilevel Feedback Queue (MLFQ) YES

macOS Hybrid of Round Robin and Priority YES


Queue

A. Example: Linux – Completely Fair Scheduler (CFS)

Each thread has a vruntime (virtual runtime)


Scheduler picks the thread with lowest vruntime (i.e., least CPU usage so far)
Tries to give fair time to all threads

CFS Tree (Red-Black Tree):

Java threads on Linux run inside this structure. JVM priority hints are ignored unless nice values or sched_setscheduler
is manually adjusted.

B. Example: Windows – Multilevel Feedback Queue (MLFQ)

Several queues for different priority levels


Threads move between queues based on behavior (CPU-bound vs IO-bound)
High priority threads preempt low priority ones

If you set a thread priority in Java (e.g. Thread.MAX_PRIORITY), Windows may give it a better queue.

5. JVM’s Role in Scheduling (Simplified View)

Although the OS decides when a thread runs, the JVM:

Tracks thread states (NEW, RUNNABLE, BLOCKED, etc.)


Passes RUNNABLE threads to the OS queue
Wakes up threads from WAITING / TIMED_WAITING when time expires or notify happens
Keeps a monitor lock table to decide which thread to unblock first

6. Java Thread Priorities - Just Hints


Java threads can have 3 predefined constants:

But:

On Linux, it’s usually ignored unless you change the thread policy.
On Windows, it can influence thread queue placement.

7. Summary Table: JVM vs OS Responsibilities

Responsibility JVM OS

Create thread object ✅ ❌

Map to native thread ✅ ✅

Schedule CPU time ❌ ✅

Handle start() and join() ✅ ❌

Respect setPriority() Hint only May respect

Detect deadlocks ✅ ❌

Context switching ❌ ✅

Kill/halt threads ✅ (deprecated) ✅

Thread finishes -> JVM sets state TERMINATED

9. What Can You Control?

Use Executors for controlled thread pools


Use Thread.setPriority() as a soft hint
Use Thread.sleep() or Thread.yield() to influence timing
For real control, use native methods or OS-level configurations (like nice, sched in Linux)

Summary

JVM does not contain its own thread scheduler, but uses the OS thread scheduler instead. Java threads are managed by the
JVM and executed by the OS based on preemptive and priority-based scheduling algorithms like CFS or MLFQ.

Thread Synchronization in Java


What is Synchronization?

When two or more threads try to access the same shared resource at the same time, data inconsistency can occur.

To prevent this, Java provides synchronization, which ensures that only one thread can access the critical section (shared
code/data) at a time.

Real-Life Analogy:

Think of a public washroom with a single key. Only one person can use it at a time. Others must wait.

That’s what synchronization does lock access to a shared resource until the current thread is done.

Problem Without Synchronization

You expect 2000, but you might get 1850, 1933, etc. because both threads are modifying count at the same time.

Solving It With Synchronization


Now only one thread at a time can enter the increment() method. This guarantees correct output: 2000

Types of Synchronization:

Method-level

Block-level (more fine-grained)

Static synchronization (locks on class-level)

Important Notes

Avoid over-synchronization: It can slow down your app.


Only use synchronization when multiple threads access shared data.
Always prefer block-level sync for better performance (lock only what's needed).

Summary

Use synchronization to protect shared resources.


synchronized ensures mutual exclusion.
You can synchronize methods or blocks.
Always balance safety and performance.

Deadlock in Java Threads What It Is, Why It Happens, and How to Avoid It

What is a Deadlock?

A deadlock is a situation where two or more threads are waiting for each other to release resources, but none of them ever
does. As a result, all the involved threads are stuck forever.

Real-Life Analogy

Imagine two people:

Person A holds Spoon and waits for Fork


Person B holds Fork and waits for Spoon

Since neither will give up what they’re holding, both are stuck this is exactly how deadlocks work in code.

How Deadlock Happens in Java (Code Example)


What happens here?

Thread 1 locks r1 and waits for r2


Thread 2 locks r2 and waits for r1

They’re both waiting forever = deadlock.

Four Conditions for Deadlock (All must be true)

1. Mutual Exclusion – Resources can't be shared


2. Hold and Wait – Thread holds one resource and waits for another
3. No Preemption – You can’t forcibly take resource from thread
4. Circular Wait – A waits for B, B waits for C, C waits for A

How to Detect Deadlock

Java doesn't throw a DeadlockException, but you can detect it using tools like:

jConsole
VisualVM
Thread Dump (analyze using jstack)

How to Avoid Deadlocks (Practical Solutions)

1. Lock Resources in Same Order

Always acquire locks in a fixed global order.


If all threads follow the same order, circular wait won't occur.

2. Use Try-Lock with Timeout (java.util.concurrent.locks.Lock)

Use ReentrantLock.tryLock() to avoid indefinite waiting.

This avoids deadlock because if a thread can’t get both locks in time, it backs off.

3. Avoid Nested Locks If Possible

The more nested locks you have, the higher the risk of deadlock.

Try to minimize deep nesting in critical sections.

4. Use Higher-Level Concurrency APIs

Use ExecutorService, synchronized collections, ConcurrentHashMap, BlockingQueue, etc., which handle low-level locking
internally.
Summary

Concept Explanation

What is Deadlock? Two or more threads waiting for each other forever

Real-life Example Two people holding one spoon/fork each, waiting for the
other

How it Happens Nested synchronized blocks with shared resources

Detection Use jConsole, jstack, thread dumps

Prevention Lock ordering, tryLock, timeout, avoid nesting, use high-


level APIs

Deadlocks are tricky but avoidable.


The key is to analyze your locking strategy, use timeouts where possible, and lean on modern concurrency utilities that are
designed to avoid such pitfalls.

You might also like