[go: up one dir, main page]

0% found this document useful (0 votes)
11 views16 pages

thread

Multithreading in Java allows concurrent execution of multiple threads to optimize CPU utilization, managed by the JVM in single-core environments and fully utilizing multiple cores in multi-core systems. The document covers thread lifecycle, creation methods, synchronization mechanisms, and advanced concepts like ReentrantLock and Executor Framework, emphasizing thread safety and communication. It also discusses issues like deadlocks, race conditions, and livelocks, providing insights into effective multithreading practices.

Uploaded by

g google
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)
11 views16 pages

thread

Multithreading in Java allows concurrent execution of multiple threads to optimize CPU utilization, managed by the JVM in single-core environments and fully utilizing multiple cores in multi-core systems. The document covers thread lifecycle, creation methods, synchronization mechanisms, and advanced concepts like ReentrantLock and Executor Framework, emphasizing thread safety and communication. It also discusses issues like deadlocks, race conditions, and livelocks, providing insights into effective multithreading practices.

Uploaded by

g google
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
You are on page 1/ 16

What is Multithreading?

In Java, multithreading is the concurrent execution of two or more threads to maximize the
utilization of the CPU. Java's multithreading capabilities are part of the java.lang package, making it
easy to implement concurrent execution.

How JVM handles multithreading?

In Single core environment, java’s multithreading is managed by the JVM and OS, which switch
between threads to give illusion of concurrency. The thread shares single core, and time slicing is
used to manage thread execution.

In multi core environment, java’s multithreading can take full advantage of the available cores. The
JVM can distribute threads across multiple cores, allowing true parallel execution of thread.

What Is Thread?

It is a lightweight process, the smallest unit of processing. Java supports multithreading through its
java.lang package

When a Java program starts, one thread begins running immediately, which is called the main thread.
This thread is responsible for executing the main method of a program.

Life Cycle of Thread

New: A thread is in this state when it is created but not yet started. In code we create a object of
thread.

Runnable: After the start method is called, the thread become runnable. It’s ready to run and is
waiting for CPU time. In code when we write thread.start().

Running: The thread is in this state when it is executing. In code Run method will get executed.

Blocked/waiting: When thread is waiting for some resource or for some another thread to perform
some action.

Terminated: A thread in this state when it has finished the execution.

Creating thread using thread class


Creating thread by implementing runnable
Thread.start(): it will start the thread execution.

Thread. Join(): it will ensure thread will finishes before moving to the execution of the next line.

We have studied that whenever we need to extend some class and use thread then we use runnable
but why? Because we cannot extend two or more classes as java does not support multiple
inheritance.

Some Inbuild function in Thread

Thread.currentThread(): give details of current running Thread.

Thread.currentThread().getName(): give name of current running Thread.

Thread.currentThread().getPriority(): give Priority of currently running Thread.

High Priority has value 10, medium has 5 and low has 1.

Note: Jaroori nahi he ki pehle saari high priority task execute hongi fir low priority wale. Ye ek hint
hota he jvm ke liye ki kisi bhi 2 me se high priority shoose karo. Ye isliye hota he kyuki hum multi core
cpu use kar rahe he jo ki ek time me 2 or use jada thread execute karenge.

Thread.interrupt(): The primary purpose of the interrupt() method in Java is to signal a thread that it
should stop or change its operation. It does not forcibly stop a thread; instead, it sets an interrupted
status flag on the thread, which must be checked by the thread's code and acted upon.

 Interrupt Blocking Operations: If a thread is in a blocking operation like Thread.sleep(),


wait(), or join(), calling interrupt() on the thread will throw an InterruptedException, allowing
the thread to exit the blocked state and handle the interruption.
Common Use Cases for Thread.interrupt()

1. Stopping a Thread Safely.


2. Interrupting a Blocked Thread (e.g., Sleeping, Waiting, or Joining).
3. Interrupting a Thread in wait() (e.g., for a Lock)

Why Thread.stop() is NOT Used (Deprecated and Unsafe)

The Thread.stop() method is not used because it forcibly stops a thread without allowing it
to clean up. This can lead to inconsistent state, resource leaks, and deadlocks in your
program.

Thread.yield(): the yield() method is part of the Thread class and provides a hint to the thread
scheduler that the current thread is willing to yield/give its execution time for other threads.
However, it does not guarantee that the thread will stop or that another thread will immediately run

Daemon Thread: daemon thread is a background thread that provides services to other threads and
does not prevent the JVM from exiting when the application’s non-daemon (user) threads finish
execution. The JVM will terminate as soon as all user threads have completed, even if daemon
threads are still running.

 A daemon thread is terminated automatically when all user threads in the program have
finished execution
 Daemon threads run in the background and are typically used for tasks like monitoring,
garbage collection, or other low-priority services.
 To mark a thread as a daemon, use the setDaemon(true) method before starting the thread.

Lambda Expression for Runnable interface


Synchronization:

It is the mechanism which ensures that two or more concurrent thread does not simultaneously
execute the same code which has shared resources to prevent from inconsistency.

Two types to achieve Synchronization:

 Synchronized Method: all the statement under method will be Synchronized.

 Synchronized Block: all the statement under block will be Synchronized.

Example for making Synchronized class.


Locks: It is an Synchronization mechanism that make sure only one thread is accessing shared
resources at a time, mean when some resources enter critical area they on the lock and when leave
lock get off. Every new thread will only enter if the lock state is off.
Java has two types of lock
Intrinsic: These are built in every object, they cannot be seen but they come to action as soon as we
use Synchronized keyword.

Extrinsic: They are more advanced and we can control them using Lock class from
java.util.concurrent.locks package. We explicitly define when to lock and unclock. ReentrantLock
class is to initialize lock object and it must be final.
Example to show why lock is required and why synchronized cannot always be used.
So, in the above code we can see thread 1 will start executing and it will go to sleep for 3 second this
sleep operation represent some database operation, as we have used synchronized, we thread 2 is
not doing any thing and must have to wait.

What is ReentrantLock in Java?

ReentrantLock is a class in java.util.concurrent.locks that provides an explicit locking mechanism


with more flexibility than synchronized. It allows the same thread to acquire the lock multiple times
without getting blocked, hence the name re-entrant.

Reentrant vs. Normal Lock (Mutex)


1. Normal Lock (Non-Reentrant Mutex)

o If a thread acquires a normal mutex and then tries to lock it again before unlocking
it, the thread blocks (waits indefinitely) because the lock is already held by the same
thread.

o This can cause a deadlock if the thread is waiting for itself.

2. Reentrant Lock

o A reentrant lock allows the same thread to acquire the lock multiple times without
blocking.

o It keeps a count of how many times the thread has acquired it.

o The thread must release the lock the same number of times before it is fully
unlocked.

How ReentrantLock Works?

Unlike synchronized, ReentrantLock must be manually locked and unlocked, giving more control over
thread synchronization.

 Reentrant Behavior: The same thread can lock multiple times, and it won’t block itself.
 Fairness Policy: You can create a fair lock (new ReentrantLock(true)) to ensure first-
come-first-serve locking.
 Interruptible Locking: Unlike synchronized, you can interrupt a waiting thread.
 Try Locking Without Waiting: Use tryLock() to avoid waiting forever.
 Multiple Condition Variables: Unlike synchronized, ReentrantLock allows multiple
conditions (Condition objects).

Now below code the second code does not have to wait for long time.
How to Ensure Fairness in ReentrantLock?

By default, ReentrantLock is not fair, meaning a thread might get the lock even if another thread has
been waiting longer. However, you can create a fair lock by passing true to the constructor:
What is ReadWrite Lock?

A ReadWriteLock in Java is a concurrency mechanism that allows multiple threads to read a resource
simultaneously while ensuring that only one thread can write to the resource at any given time. It
improves performance by allowing multiple readers when no writer is present.

Java provides ReentrantReadWriteLock from the java.util.concurrent.locks package, which


implements ReadWriteLock and provides:

 A read lock (lock.readLock()) for multiple readers.

 A write lock (lock.writeLock()) for a single writer.

What is Deadlock?

Deadlock is a situation in multithreading where two or more threads are blocked forever, waiting for
each other to release a resource. This typically occurs when two or more threads have circular
dependencies on a set of locks.

For Example, let suppose there are 2 thread A and B A has pen and B has copy and both required pen
and copy to execute and both are waiting for each other to release resources. They are in cyclic
dependency and hence are in deadlock.

Deadlocks typically occur when four conditions are met simultaneously:

 Mutual Exclusion: Only one thread can access a resource at a time.


 Hold and Wait: A thread holding at least one resource is waiting to acquire additional
resources held by other threads.
 No Preemption: Resources cannot be forcibly taken from threads holding them.
 Circular Wait: A set of threads is waiting for each other in a circular chain.
To avoid deadlock there are 2 solutions

Solution 1 ***Always acquire locks in a consistent order.


Solution 2 ***Using ReentrantLock with tryLock().

 Instead of waiting indefinitely, tryLock(timeout, TimeUnit) tries to acquire the lock within a
specified time.

 If the lock cannot be acquired within that time, the thread gives up and releases any
previously acquired locks.

 This prevents the situation where two threads are stuck waiting for each other.

Thread Communication

In multithreaded environment threads often need to communicate and coordinate with each other
to accomplish a task.
without proper communication mechanism thread may go into busy state and wastage of CPU
resources and Also to the Deadlock.

Java provides three key methods in the Object class for thread communication.

 wait(): Causes the current thread to release the lock and wait until another thread invokes
notify() or notifyAll() on the same object.

 notify(): Wakes up a single thread that is waiting on the object's monitor.

 notifyAll(): Wakes up all threads waiting on the object's monitor.

Thread must continuously check the state of resources and locks, which wastes CPU resources. In
thread communication, threads have the ability to notify each other, so a waiting thread does not
need to continuously check.

Producer & Consumer problem

The Producer-Consumer problem is a classic synchronization problem in multithreading where


multiple producer threads generate data and place it into a shared buffer, while multiple consumer
threads retrieve and process the data. The challenge is to ensure that producers do not overwrite a
full buffer and consumers do not read from an empty buffer, avoiding race conditions and deadlocks.
what is callable?

In Java, Callable is an interface from the java.util.concurrent package that represents a task that
returns a result and may throw an exception. It is similar to Runnable, but with additional capabilities

What is Race on condition?

A race condition in a multithreaded environment occurs when multiple threads access shared
resources concurrently, and the final outcome depends on the timing of their execution. This can
lead to unexpected behavior or incorrect results because the threads are competing to modify the
resource.
What is Livelock in a Multithreaded Environment?

A livelock occurs when two or more threads keep responding to each other’s actions but fail to make
progress. Unlike a deadlock (where threads are stuck waiting indefinitely), in a livelock, threads keep
changing state but never move forward to complete their tasks.

Think of two people stepping aside to avoid each other in a narrow hallway—both keep moving but
remain stuck in a loop.

What Does "Thread Safe" Mean?

A piece of code or a program is thread-safe if multiple threads can access and modify shared data
without causing race conditions, data corruption, or unpredictable behavior.

What is Executer Framework?

The Executor Framework in Java is a high-level API that provides a way to manage and control thread
execution efficiently. It introduces a thread pool mechanism, allowing tasks to be executed
asynchronously without manually creating and managing threads.

Problems with Manual Thread Management? Why Executer Framework better?

Thread Creation is Expensive

 Creating a new thread for every task consumes a lot of system resources (CPU & memory).
 Solution: The Executor Framework reuses threads, reducing overhead.

Limited Control Over Thread Pools

 If we create too many threads, the system might run out of resources (Too many threads =
Too much context switching).
 Solution: Executors provide optimized thread pools (fixed, cached, scheduled).

No Built-in Support for Task Queuing

🔹 Manually handling a queue of tasks for threads is complex.


🔹 Solution: Executors maintain a queue of pending tasks and assign them to
available threads.

Different Ways to Create an Executor Thread in Java?


Using newFixedThreadPool(int n)

✅ Creates a fixed number of threads (n).


✅ If all threads are busy, new tasks wait in a queue.

Using newCachedThreadPool()

✅ Creates unlimited threads as needed.


✅ If a thread is inactive for 60 seconds, it is removed.
✅ Suitable for many short-lived tasks.

Using newSingleThreadExecutor()

✅ Uses only one thread to execute tasks sequentially.


✅ Ensures thread-safety and ordered execution.

Using newScheduledThreadPool(int n) (For Scheduled Tasks)

✅ Supports delayed execution or periodic task scheduling.


✅ Good for scheduled background tasks.

You might also like