0% found this document useful (0 votes)
6 views39 pages

Multithreading in Java

The document provides an extensive overview of multithreading in Java, covering concepts such as multiprogramming, multitasking, multiprocessing, and multithreading. It explains the differences between these concepts, the lifecycle of a thread, and methods for creating threads in Java. Additionally, it details the advantages of multithreading, the Java Thread class, and various thread methods.

Uploaded by

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

Multithreading in Java

The document provides an extensive overview of multithreading in Java, covering concepts such as multiprogramming, multitasking, multiprocessing, and multithreading. It explains the differences between these concepts, the lifecycle of a thread, and methods for creating threads in Java. Additionally, it details the advantages of multithreading, the Java Thread class, and various thread methods.

Uploaded by

bhumakarthik1906
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

1

CO4 – Multithread in Java


--------------------------------------------------------------------------------------------------------------------------
Index:
1. Multi Programming, Multi Processing, Mukti tasking and Multi treading --Page No:2
2. Multithreading in Java –Page No: 5
3. Creating Threads in Java ---Page No:8
4. Life cycle of a Thread (Thread States) –Page No: 9
5. Thread class constructor – Page No: 11
6. Thread Methods -- Page No: 12
7. Thread Scheduler in Java: -- Page No: 13
8. . Concurrency In Java - Thread Pool and Executor Framework in Java – Page No:14
9. Thread Synchronization and Locks – Page No: 20
10. Inter-thread Communication in Java -- Page No: 27
11. Deadlocks – Page No: 35
2

1. Multi Programming , Multi Processing, Multi tasking and Multi threading concepts:
1. Multiprogramming

Definition: Multiprogramming is a method where multiple programs are loaded into memory and executed by the
CPU one after the other. The CPU switches between programs, giving the illusion that they are running
simultaneously, although at any given time, only one program is actually executing.

Real-Time Example: Imagine you are listening to music on your computer while also working on a Word document
and downloading a file from the internet. The operating system manages these tasks by keeping all three programs
(music player, Word processor, and browser) in memory. The CPU switches between these tasks quickly, making it
appear as though all are happening simultaneously.

2. Multitasking

Definition: Multitasking is the ability of an operating system to execute multiple tasks (programs or threads)
seemingly at the same time. This is achieved through time-sharing where the CPU rapidly switches between tasks so
quickly that it appears as if the tasks are running simultaneously.

How It Works: In multitasking, the operating system divides CPU time into small segments, called time slices. Each
task gets a time slice, and the CPU switches between tasks after each slice. This happens so fast (milliseconds) that
users perceive that all tasks are running at the same time.

For Instance -

 The CPU executes part of Task A for a few milliseconds, then switches to Task B for another few milliseconds,
and so on.
 If Task A needs to wait (e.g., for I/O), the CPU immediately switches to Task B without waiting.
 Preemptive multitasking is the most common type, where the operating system forcibly switches between
tasks based on priority and time slice.

Real-Time Example: On your smartphone, you might be chatting with a friend on WhatsApp while also receiving
emails in the background and listening to music. The operating system handles these tasks by giving each a small
time slice, creating the appearance that they are all happening at once.
3

Benefits:

 Improve performance of CPU


 Multi-Tasking can be achieved by two ways.
1. Process-based multi tasking (Multi-Processing) and
2. Thread-based multi tasking.(Multi-Threading)

3. Multiprocessing

Definition: Multiprocessing refers to the ability of a system to use more than one processor (CPU cores) to execute
multiple processes simultaneously. Each CPU can execute a different process at the same time.

 A multiprocessing system is one which has more than two processors.


 Multiprocessing is the ability for computers to complete multiple tasks at the same time without having to
wait for one task to complete before the next task can be started. A dual-core processor is twice as fast as a
single processor, and a quad-core processor is four times as fast.
 When one System connected to Multiple Processors in order to complete the task.

Real-Time Example: In modern computers with multi-core processors, each core can handle a separate task. For
instance, while one core might be running a video game, another could be rendering a video, and a third might be
scanning the system for viruses. All these tasks happen in parallel because each core is independently processing its
own task.

 It is best suitable for system level performance.

4. Multithreading

Definition: Multithreading is a technique where a single process can have multiple threads (sub process) running
concurrently, each performing a different part of the task. It allows for better utilization of CPU resources within a
single application.

Real-Time Example: Consider a web browser that can load multiple web pages at once. Each tab represents a thread.
While one thread is loading a video in one tab, another thread might be downloading images in a different tab, and
yet another might be processing JavaScript for another webpage. These threads all belong to the same process (the
web browser) but work on different tasks concurrently.

Benefits:

 Software
 Animations
 Games

Real Time - Example: Single Process (Gas Stove) with Four Burners (Threads)
4

Difference between Multi programming, Multi tasking, Multi Processing and Multi threading:
Feature Multiprogramming Multitasking Multiprocessing Multithreading

Definition Running multiple Running Running multiple Running multiple


programs on a single multiple tasks processes on threads within a
CPU (applications) multiple CPUs (or single task
on a single CPU cores) (application)
Resource Resources (CPU, Resources (CPU, Each process has Resources (CPU,
Sharing memory) are shared memory) are its own set of memory) are
among programs shared among resources (CPU, shared among
tasks memory) threads
Scheduling Uses round-robin or Uses priority- Each process can Uses priority-
priority-based based or time- have its own based or time-
scheduling to allocate slicing scheduling slicing scheduling
CPU time to programs scheduling to algorithm to allocate CPU
allocate CPU time to threads
time to tasks
Memory Each program has its Each task has its Each process has Threads share
Management own memory space own memory its own memory memory space
5

space space within a task


Context Requires a context Requires a Requires a Requires a context
Switching switch to switch context switch context switch to switch to switch
between programs to switch switch between between threads
between tasks processes
Inter-Process Uses message passing Uses message Uses inter- Uses thread
Communication or shared memory for passing or process synchronization
(IPC) IPC shared memory communication mechanisms (e.g.,
for IPC mechanisms locks,
(e.g., pipes, semaphores) for
sockets) for IPC IPC

 Multi threading is best suitable at programming level


 Java provides Pre-defined API for Multi-threading concept such as:
1. Thread class
2. Runnable Interface
3. ThreadGroup
4. Concurrency
5. ThreadPool

etc……

2. Multithreading in Java:
1. Introduction to Multithreading

Multithreading is a process of executing multiple threads simultaneously. In Java, each thread is an independent path
of execution, and it can run concurrently with other threads to perform tasks like file I/O, calculations, or background
operations.

Threads in java:
6

What is Thread?

 A thread is a lightweight subprocess, the smallest unit of processing. It is a separate path of execution.
 Threads are independent. If there occurs exception in one thread, it doesn't affect other threads. It uses a
shared memory area.
 However, we use multithreading than multiprocessing because threads use a shared memory area. They
don't allocate separate memory area so saves memory, and context-switching between the threads takes less
time than process.
 Java Multithreading is mostly used in games, animation, etc.

Advantages of Java Multithreading:

1) It doesn't block the user because threads are independent and you can perform multiple operations at the same
time.

2) You can perform many operations together, so it saves time.

3) Threads are independent, so it doesn't affect other threads if an exception occurs in a single thread.

Multitasking

Multitasking is a process of executing multiple tasks simultaneously. We use multitasking to utilize the CPU.
Multitasking can be achieved in two ways:

o Process-based Multitasking (Multiprocessing)

o Thread-based Multitasking (Multithreading)

1) Process-based Multitasking (Multiprocessing)

o Each process has an address in memory. In other words, each process allocates a separate memory area.

o A process is heavyweight.

o Cost of communication between the process is high.

o Switching from one process to another requires some time for saving and loading registers, memory maps,
updating lists, etc.

2) Thread-based Multitasking (Multithreading)

o Threads share the same address space.

o A thread is lightweight.

o Cost of communication between the thread is low.

Note: At least one process is required for each thread.


7

As shown in the above figure, a thread is executed inside the process. There is context-switching between the
threads. There can be multiple processes inside the OS, and one process can have multiple threads.

Note: At a time one thread is executed only.

Java thread vs. Java process: what is the difference:

 A Java process is a program in execution. A Java thread is a subset of a Java process.

 A Java process consists of multiple threads and a Java thread is often regarded as a light-weight process.

Real-Life Scenario to understand Process and Threads:


School:

 Multiprocessing: Imagine a school with multiple classrooms, each conducting different activities
simultaneously. Each classroom represents a separate process. For instance, one classroom might be holding
a math class, another might be teaching history, and a third might be conducting a science experiment. Each
classroom operates independently, with its own teacher and resources. If there’s an issue in one classroom, it
won’t affect the others.

 Multithreading: Alternatively, within a single classroom, there are different tasks being performed
concurrently. For example, while the teacher is lecturing at the front of the class, students might be working
on assignments, asking questions, or discussing topics in groups. These tasks can be seen as threads within
the same process (classroom). They share resources such as the classroom space, textbooks, and the
teacher’s attention. Multithreading in this scenario allows for better utilization of resources and fosters
collaboration among students.

Key Differences Between Multiprocessing and Multithreading


1. The key difference between multiprocessing and multithreading is that multiprocessing allows a system to
have more than two CPUs added to the system whereas multithreading lets a process generate multiple
threads to increase the computing speed of a system.

2. Multiprocessing system executes multiple processes simultaneously whereas, the multithreading system let
execute multiple threads of a process simultaneously.

3. Creating a process can consume time and even exhaust the system resources. However creating threads
is economical as threads belonging to the same process share the belongings of that process.

-----------------------------------------------------------------------------------------------------------------------------------------------------------
8

3. Creating Threads in Java:


Threads can be created in two ways:
1. By extending Thread class
2. By implementing Runnable interface
Thread Class and Runnable Interface:

Thread Class: Java provides the Thread class, which represents a thread of execution in a program. To create a
thread, you can either extend the Thread class or implement the Runnable interface.

Runnable Interface: The Runnable interface should be implemented by any class whose instances are intended to be
executed by a thread. It has a single method, run().

Creating a Thread by Extending Thread Class

Explanation: In this example, MyThread extends the Thread class and overrides the run() method. The start() method
begins the execution of the thread, which in turn calls the run() method.

Creating a Thread by Implementing Runnable Interface

Explanation: MyRunnable implements the Runnable interface and overrides the run() method. A Thread object is
created by passing an instance of MyRunnable to the Thread constructor.

-----------------------------------------------------------------------------------------------------------------------------------
9

[Link] cycle of a Thread (Thread States)


In Java, a thread can be in any of the five following states

[Link] State

[Link] State

[Link] State

4. Blocked State

5. Dead State

New: Whenever a new thread is created, it is always in the new state. For a thread in the new state, the code has not
been run yet and thus has not begun its execution.

Active: When a thread invokes the start() method, it moves from the new state to the active state. The active state
contains two states within it: one is runnable, and the other is running.

o Runnable: A thread, that is ready to run is then moved to the runnable state. In the runnable state, the
thread may be running or may be ready to run at any given instant of time. It is the duty of the thread
scheduler to provide the thread time to run, i.e., moving the thread the running state.
A program implementing multithreading acquires a fixed slice of time to each individual thread. Each and
every thread runs for a short span of time and when that allocated time slice is over, the thread voluntarily
gives up the CPU to the other thread, so that the other threads can also run for their slice of time. Whenever
such a scenario occurs, all those threads that are willing to run, waiting for their turn to run, lie in the
runnable state. In the runnable state, there is a queue where the threads lie.

o Running: When the thread gets the CPU, it moves from the runnable to the running state. Generally, the
most common change in the state of a thread is from runnable to running and again back to runnable.

Blocked or Waiting: Whenever a thread is inactive for a span of time (not permanently) then, either the thread is in
the blocked state or is in the waiting state.
10

Example Program of Thread Life Cycle:


11

The Main Thread:


 When we run any java program, the program begins to execute its code starting from the main method.
 The JVM creates a thread to start executing the code present in main method. This thread is called as main
thread.
 Although the main thread is automatically created, you can control it by obtaining a reference to it by calling
currentThread() method.
 Two important things to know about main thread are,
o It is the thread from which other threads will be produced.
o main thread must be always the last thread to finish execution.

Example:

-----------------------------------------------------------------------------------------------------------------------------------

[Link] class constructor:


Thread class provide constructors and methods to create and perform operations on a thread.
Thread class extends Object class and implements Runnable interface.
Commonly used Constructors of Thread class:
• Thread()
• Thread(String name)
• Thread(Runnable r)
• Thread(Runnable r, String name)
Example1: Thread(String name)

Example 2: Thread(Runnable r, String name)


12

----------------------------------------------------------------------------------------------------------------------------------

[Link] Methods
1. public void run(): is used to perform action for a thread.
2. public void start(): starts the execution of the [Link] calls the run() method on the thread.
3. public void sleep(long miliseconds): Causes the currently executing thread to sleep (temporarily
cease execution) for the specified number of milliseconds.
4. public void join(): waits for a thread to die.
5. public void join(long miliseconds): waits for a thread to die for the specified miliseconds.
6. public int getPriority(): returns the priority of the thread.
7. public int setPriority(int priority): changes the priority of the thread.
8. public String getName(): returns the name of the thread.
9. public void setName(String name): changes the name of the thread.
10. public Thread currentThread(): returns the reference of currently executing thread.
11. public int getId(): returns the id of the thread.
12. public [Link] getState(): returns the state of the thread.
13. public boolean isAlive(): tests if the thread is alive.
14. public void yield(): causes the currently executing thread object to temporarily pause and allow
other threads to execute.
15. public void suspend(): is used to suspend the thread(depricated).
16. public void resume(): is used to resume the suspended thread(depricated).
17. public void stop(): is used to stop the thread(depricated).
18. public boolean isDaemon(): tests if the thread is a daemon thread.(a tread which runs background)
19. public void setDaemon(boolean b): marks the thread as daemon or user thread.
13

20. public void interrupt(): interrupts the thread.


21. public boolean isInterrupted(): tests if the thread has been interrupted.
22. public static boolean interrupted(): tests if the current thread has been interrupted.
Example: Thread Methods

-----------------------------------------------------------------------------------------------------------------------------------

[Link] Scheduler in Java:


Thread Priorities:
Each thread has a priority. Priorities are represented by a number between 1 and 10. In most cases, the thread
scheduler schedules the threads according to their priority (known as preemptive scheduling). But it is not
guaranteed because it depends on JVM specification that which scheduling it chooses. Note that not only JVM a Java
programmer can also assign the priorities of a thread explicitly in a Java program.

Priority: Priority of each thread lies between 1 to 10. If a thread has a higher priority, it means that thread has got a
better chance of getting picked up by the thread scheduler.

Time of Arrival: Suppose two threads of the same priority enter the runnable state, then priority cannot be the
factor to pick a thread from these two threads. In such a case, arrival time of thread is considered by the thread
scheduler. A thread that arrived first gets the preference over the other threads.
14

Setter & Getter Method of Thread Priority:

public final int getPriority(): The [Link]() method returns the priority of the given thread.

public final void setPriority(int newPriority): The [Link]() method updates or assign the priority
of the thread to newPriority. The method throws IllegalArgumentException if the value newPriority goes out of the
range, which is 1 (minimum) to 10 (maximum).

There are three constants defined in Thread class:

 public static int MIN_PRIORITY (1)


 public static int NORM_PRIORITY (5)
 public static int MAX_PRIORITY (10)

Default priority of a thread is 5 (NORM_PRIORITY). The value of MIN_PRIORITY is 1 and the value of MAX_PRIORITY is
10.

Example Program:

----------------------------------------------------------------------------------------------------------------------------------------------------------

8. Concurrency In Java - Thread Pool and Executor Framework in Java


Java provides the Executor framework, which simplifies thread management by offering a mechanism to efficiently
manage and reuse threads in the form of a thread pool. The thread pool reuses existing threads to execute multiple
tasks instead of creating new threads for each task.

1. Thread Pool:

o A thread pool is a collection of threads (also called as Worker threads) that can be used to perform a
set of tasks concurrently.

o These threads are used to execute tasks submitted to the pool, thus reducing the overhead of thread
creation and destruction.
15

o When we use a thread pool, we write our concurrent code in the form of parallel tasks and submit
them for execution to an instance of a thread pool. This instance controls several re-used threads for
executing these tasks

2. Executor Framework:

o The Executor framework in Java provides a higher-level API for managing threads.

o It decouples the task submission from the actual mechanism used to execute the task, whether it’s a
single thread, a thread pool, or something else.

Thread Pools
A Thread Pool is a collection of pre-initialized threads that stand by ready to execute tasks. Instead of creating a new
thread for each task, tasks are submitted to the pool, which assigns them to available threads. This approach offers
several advantages:

Performance: Reusing threads reduces the overhead of thread creation and destruction.

Resource Management: Limits the number of concurrent threads, preventing resource exhaustion.

Task Management: Provides mechanisms to handle task queuing, scheduling, and execution policies.

What is the Executor Framework?


The Executor Framework is part of the [Link] package introduced in Java 5. It provides a high-level API
for managing and controlling thread execution. The core interfaces and classes include:

Components of the Executor Framework:

I. Executor Interface:
 The root interface for executing tasks.
 It has a single method:

II. ExecutorService Interface:


 A sub-interface of Executor, it provides methods to manage the lifecycle of threads and obtain Future objects
to track task completion.
III. ScheduledExecutorService Interface:
 A sub-interface of ExecutorService, used for scheduling tasks to run after a delay or periodically.
IV. ThreadPoolExecutor Class:
 Provides a flexible thread pool implementation.
V. Executors Utility Class:
16

 Provides factory methods for creating thread pools.

In order to use the executor framework, we have to create a thread pool for executing the task by
submitting that task to that thread pool.
A framework having a bunch of components that are used for managing worker threads efficiently is
referred to as Executor Framework. The Executor API reduces the execution of the task from the actual task
to be executed through the Executors. The executor framework is an implementation of the Producer-
Consumer pattern. class provides a set of methods for creating ThreadPools of worker threads.
Thread pools overcome this issue by keeping the threads alive and reusing the threads. Any excess tasks
flowing in, that the threads in the pool can’t handle are held in a Queue. Once any of the threads get free,
they pick up the next task from this queue. This task queue is essentially unbounded for the out-of-box
executors provided by the JDK.
Types of Thread Pools

Java's Executor Framework provides several types of thread pools, each suited for different scenarios.

a) FixedThreadPool

A fixed-size thread pool with a set number of threads. If all threads are busy, new tasks wait in the queue until a
thread becomes available.

Example 1: Using FixedThreadPool

A fixed thread pool is useful when you know the number of tasks, and they are computationally expensive.

Scenario: Suppose you have a set of tasks (e.g., processing customer orders) that need to be executed concurrently,
but you want to limit the number of threads to prevent resource exhaustion.
17

b) CachedThreadPool

A thread pool that creates new threads as needed but reuses previously constructed threads when available. Suitable
for executing many short-lived tasks.

If all threads are busy, then create a new thread for the task and place it in the pool.

If thread is idle for 60 seconds (no task to execute) then kill the thread.

Example 2: Using CachedThreadPool

A cached thread pool is ideal for tasks that are short-lived and might vary in number.

Scenario: You have numerous short-lived tasks (e.g., handling web requests) that can be executed concurrently
without worrying about the number of threads.
18

c) SingleThreadExecutor

A thread pool with only one thread. Tasks are executed sequentially, ensuring order and avoiding concurrency issues.

Example 3: Using SingleThreadPool

A single-threaded executor executes tasks sequentially, ensuring that only one task is running at any given time.
19

d) ScheduledThreadPool

A thread pool that can schedule commands to run after a given delay or to execute periodically.

Example 4: Using ScheduledThreadPool

This type of thread pool is used when you want to schedule tasks to execute after some delay or periodically.

Scenario: You need to schedule tasks to run after a delay or periodically (e.g., sending periodic reports).

Advantages of Thread Pool and Executor Framework:

Better resource management: Avoids the overhead of creating and destroying threads repeatedly.

Improved performance: Tasks are executed efficiently using a fixed or dynamically growing number of threads.

Ease of use: With built-in classes and methods, Java’s Executor framework simplifies the complexity of thread
management.

Task Scheduling: The ScheduledExecutorService can easily schedule tasks for future execution.

-----------------------------------------------------------------------------------------------------------------------------------------------------------

Java Callable Interface:

Java provides two approaches for creating threads one by implementing the Runnable interface and the other by
inheriting the Thread class. However, one important feature missing with the implementation of the Runnable
interface is that it is not possible for a thread to return something when it completes its execution, i.e., when the
run() method execution is over. In order to support this feature, the Java Callable interface is used.
20

Callable vs Runnable:

For implementing Runnable, the run() method needs to be implemented which does not return anything, while for a
Callable, the call() method needs to be implemented which returns a result on completion. Note that a thread can’t
be created with a Callable, it can only be created with a Runnable.

Another difference is that the call() method can throw an exception whereas run() cannot

Syntax:

public Object call() throws Exception;

-----------------------------------------------------------------------------------------------------------------------------------------------------------

[Link] Synchronization and Locks:


Problem with Multithreading in Java
21

 Synchronization is essential when multiple threads access shared resources. Without synchronization, it may
lead to data inconsistency.
 Synchronization in Java is the capability to control the access of multiple threads to any shared resource.
 Java Synchronization is a better option where we want to allow only one thread to access the shared
resource.

Why use Synchronization?

The synchronization is mainly used to

1. To prevent thread interference.

2. To prevent consistency problem.

Types of Synchronization

There are two types of synchronization

1. Process Synchronization

2. Thread Synchronization

Thread Synchronization

There are two types of thread synchronization mutual exclusive and inter-thread communication.

1. Mutual Exclusive

1. Synchronized method.

2. Synchronized block.

3. Static synchronization.

2. Cooperation (Inter-thread communication in java)

Mutual Exclusive

Mutual Exclusive helps keep threads from interfering with one another while sharing data. It can be achieved by
using the following three ways:

i. By Using Synchronized Method


ii. By Using Synchronized Block
iii. By Using Static Synchronization
22

i).Synchronized Method: A method can be synchronized by using the synchronized keyword

Example of Synchronized Method:


23

ii).Synchronized Block: A block of code can be synchronized to allow only one thread to execute it at a time.
24

Example of Synchronized block:

iii).Static synchronization: Static Synchronized method is also a method of synchronizing a method in Java such that
no two threads can act simultaneously static upon the synchronized method. The only difference is by using Static
Synchronized. We are attaining a class-level lock such that only one thread will operate on the method. The Thread
will acquire a class-level lock of a Java class, such that only one thread can act on the static synchronized method.

Note: When a class has both synchronized and static synchronized methods they can run parallelly ,as those two
methods require different locks.

Let us assume that there are 6 threads. The order of execution will be as follows:
25

Example of static synchronized:


26

Difference between Synchronization and static synchronization:

LOCKs:
Synchronization is built around an internal entity known as the lock or monitor. Every object has a lock associated
with it.

By convention, a thread that needs consistent access to an object's fields has to acquire the object's lock before
accessing them, and then release the lock when it's done with them.

The lock() method

The lock() method is one of the most important methods of the Lock interface. It is used for acquiring the lock. For
thread scheduling purposes, the current thread becomes disabled when the lock is not available. The lock() method
is a public method that returns void.

Syntax:

public void lock()

The lockInterruptibly() method

The lockInterruptibly() method is another important method of Lock interface that is used for acquiring the lock
unless the current thread is interrupted. It acquires and returns a lock immediately if it is available.

Syntax:

public void lockInterruptibly()

The tryLock() method

The tryLock() method is mainly used at the time of invocation for acquiring the lock. It returns the lock immediately
with the Boolean value true when the lock is available. It returns the Boolean value false when the lock is not
available.

The tryLock() method take no parameters and return the Boolean value.

Syntax:

public boolean tryLock()

---------------------------------------------------------------------------------------------------------------------------------------------------------
27

[Link]-thread Communication in Java:


 Inter-thread communication or Co-operation is all about allowing synchronized threads to communicate with
each other.
 Inter-thread communication is important when you develop an application where two or more threads
exchange some information.

Inter-thread Communication through wait() , notify() or notifyAll() methods:


Cooperation (Inter-thread communication) is a mechanism in which a thread is paused running in its critical section
and another thread is allowed to enter (or lock) in the same critical section to be [Link] is implemented by
following methods of Object class:

 wait()
 notify()
 notifyAll()

i) wait() method
The wait() method causes current thread to release the lock and wait until either another thread
invokes the notify() method or the notifyAll() method for this object, or a specified amount of time
has elapsed.
The current thread must own this object's monitor, so it must be called from the synchronized
method only otherwise it will throw exception.

ii) notify() method


The notify() method wakes up a single thread that is waiting on this object's monitor. If any threads
are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and
occurs at the discretion of the implementation.
28

Understanding the process of inter-thread communication:

 Threads enter to acquire lock.


 Lock is acquired by on thread.
 Now thread goes to waiting state if you call wait() method on the object. Otherwise it
releases the lock and exits.
 If you call notify() or notifyAll() method, thread moves to the notified state (runnable state).
 Now thread is available to acquire lock.
 After completion of the task, thread releases the lock and exits the monitor state of the
object.
Difference between wait and sleep:
29

Example of Interthread Communication:

Use Case:

Note:
While Producer producing items then Consumer should not Consume the items and Vice versa.
At a time either Producer or Consumer have to be occupied shared memory.

USE CASE 1: Producer – Consumer problem using wait (), notify() and notifyAll() methods:
30

Inter-Thread Communication through Blocking Queue Interface:

USE CASE 2: Producer-Consumer problem using BlockingQueue Interface:


Blocking Queue:
BlockingQueue is a queue that additionally supports operations that wait for the queue to become non-empty when
we are trying to retrieve an element, and wait for the space to be empty when an element is to be inserted in the
queue. Java 1.5 provides support for BlockingQueue interface along with other concurrent utility classes.

A BlockingQueue does not accept null elements. If we try to add a null value the implementation throws a
NullPointerException.
31

BlockingQueue Implementing Classes:

1. ArrayBlockingQueue
2. DelayQueue
3. LinkedBlockingDeque
4. LinkedBlockingQueue
5. LinkedTransferQueue
6. PriorityBlockingQueue
7. SynchronousQueue

Methods that block the operation

i. put( ): The method inserts an element to the BlockingQueue. If in case the queue is full, the put( ) method waits
until the queue has some vacant space to insert an element.

ii. take( ): The method removes and returns an element from the BlockingQueue. If in case the queue is empty, the
take( ) method waits until the queue has some elements to be deleted.

BlockingQueue Types

There are two types of BlockingQueue:

1. Unbounded Queue: Unbounded blocking queue is the queue that never blocks because its size could be grown to
a very large size. The capacity of the BlockingQueue will be set to Integer.MAX_VALUE. When the elements are
added, the size of the Unbounded queue grows.

2. Bounded Queue: Another type of the blocking queue is the bounded queue. It can be created by passing the
capacity of the queue to the constructor of the queue.
32

Example program:
33

Semaphore in Java:
Thread Coordination through Semaphore in Java:
In multithreading, coordination between threads is crucial to avoid issues such as race conditions or deadlocks. A
Semaphore in Java is used to control access to a resource by multiple threads. It allows a fixed number of threads to
access a shared resource simultaneously. The Semaphore maintains a counter, which is decremented when a thread
acquires the semaphore and incremented when a thread releases it.

Working of Semaphore:

Acquire: When a thread wants to access a resource, it calls acquire() on the semaphore. If the semaphore's counter
is greater than zero, it decrements the counter and allows the thread to proceed. If the counter is zero, the thread is
blocked until another thread releases the semaphore.

Release: When a thread is done with the resource, it calls release() on the semaphore, which increments the counter
and allows a blocked thread (if any) to acquire the semaphore.

Semaphore controls over the shared resource through a counter variable. The counter is a non-negative value. It
contains a value either greater than 0 or equal to 0.

 If counter > 0, the thread gets permission to access the shared resource and the counter value is
decremented by 1.

 Else, the thread will be blocked until a permit can be acquired.

 When the execution of the thread is completed then there is no need for the resource and the thread
releases it. After releasing the resource, the counter value incremented by 1.

 If another thread is waiting for acquiring a resource, the thread will acquire a permit at that time.

 If counter = 0, the thread does not get permission to access the shared resource.
34

Types of Semaphores

In Java, there are two types of semaphores, based on their behavior and the way they manage permits:

1. Counting Semaphore (Unfair Semaphore):


 This is the default type of semaphore in Java, often referred to simply as Semaphore.
 It allows a set number of threads to access a shared resource concurrently.
 The order in which threads acquire permits is not guaranteed to be fair. A thread that requests a permit may
obtain it before another thread that requested earlier, depending on the internal scheduling of the threads.
Key Characteristics:

 No guarantee of fairness.
 It is the most performant version, as it does not manage the order of waiting thread
 This is the default semaphore and is widely used for general-purpose scenarios.
 The order of acquiring permits is not guaranteed to be in any specific sequence, meaning that threads may
get permits in a random or arbitrary order based on thread scheduling.
 It is ideal for scenarios where fairness is not a requirement, and the main goal is to optimize performance

Syntax:

Example Program:

2. Fair Semaphore:

 A fair semaphore ensures that threads acquire permits in the order they requested them, i.e., first-come,
first-served (FIFO order).
 To create a fair semaphore, you pass true to the Semaphore constructor when creating it.

Syntax:

Key Characteristics:

 Ensures fairness: threads acquire permits in the order they requested them.
35

 Slightly slower compared to the default (unfair) semaphore due to the overhead of maintaining the fairness.

Example Program:

11. Deadlocks:
Deadlock in java is a programming situation where two or more threads are blocked forever. Java deadlock situation
arises with at least two threads and two or more resources. Here I have written a simple program that will cause java
deadlock scenario and then we will see how to analyse it.

synchronized keyword is used to make the class or method thread-safe which means only one thread can have the
lock of the synchronized method and use it, other threads have to wait till the lock releases and anyone of them
acquire that lock.

It is important to use if our program is running in a multi-threaded environment where two or more threads execute
simultaneously. But sometimes it also causes a problem which is called Deadlock. Below is a simple example of the
Deadlock condition.
36

DeadLock Example Program:

Detecting Deadlocks:

Deadlocks are hard to detect automatically, but Java provides some tools to help detect them:

[Link]: This command-line tool shows the state of all threads in a JVM, including deadlocks. It is useful for analyzing
thread dumps.

 To use jstack, find the process ID (PID) of your Java application and run
 The output will include information about any deadlocked threads.

[Link]: This graphical tool monitors the JVM in real-time. It can analyze thread activity and detect deadlocks.
37

[Link]: You can use the ThreadMXBean class from the [Link] package to
programmatically detect deadlocks.

Example Program:

Ways of avoid deadlock:

Although it is not possible to avoid deadlock condition but we can avoid it by using the following ways

i).Avoid Nested Locks — You must avoid giving locks to multiple threads, this is the main reason for a deadlock
condition. It normally happens when you give locks to multiple threads.

ii).Avoid Unnecessary Locks — The locks should be given to the important threads. Giving locks to the unnecessary
threads that cause the deadlock condition.

iii).Using Thread Join — A deadlock usually happens when one thread is waiting for the other to finish. In this case,
we can use [Link] with a maximum time that a thread will take.

12. SYNCHRONIZED COLLECTIONS & PARALLEL PROGRAMMING:


Synchronized collections are designed to allow safe access and modification of data in a multi-
threaded environment. By default, the collections in Java (like ArrayList, HashSet, HashMap, etc.)
are not thread-safe. To avoid concurrency issues like data inconsistency and race conditions, the
synchronized collections were introduced using methods from the [Link] class.

The [Link]() methods provide a simple way to wrap non-synchronized


collections like ArrayList, HashSet, and HashMap into synchronized versions.
Wrapper Methods:
Java provides several wrapper methods for synchronization:
1. [Link]()
2. [Link]()
3. [Link]()
4. [Link]()
38

5. [Link]()
These methods return a synchronized (thread-safe) version of the collection passed to them.
How It Works

When you use [Link](), the resulting synchronized collection applies a lock on each method
that modifies or accesses the collection. This ensures that only one thread can perform operations on the collection
at any given time. However, it doesn't synchronize iterators, which requires additional steps to ensure safety during
iteration.

Example Program: [Link]()

Example Program : [Link]()


39

Example Program : [Link]()

You might also like