0% found this document useful (0 votes)
9 views31 pages

Con Currency

Java provides four main methods to create threads: extending the Thread class, implementing the Runnable interface, using Callable and Future, and utilizing ExecutorService for thread pooling. Each method has its pros and cons, with ExecutorService being the recommended approach for managing multiple threads efficiently. Additionally, atomicity is crucial in ensuring safe updates in multithreading, preventing race conditions, and maintaining data integrity.

Uploaded by

vksvks03
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)
9 views31 pages

Con Currency

Java provides four main methods to create threads: extending the Thread class, implementing the Runnable interface, using Callable and Future, and utilizing ExecutorService for thread pooling. Each method has its pros and cons, with ExecutorService being the recommended approach for managing multiple threads efficiently. Additionally, atomicity is crucial in ensuring safe updates in multithreading, preventing race conditions, and maintaining data integrity.

Uploaded by

vksvks03
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/ 31

What are the different ways to create a thread in Java?

In Java, there are four main ways to create a thread:

1. Extending the Thread class

By extending the Thread class, we override the run() method and start the thread using start().

Example:

java

CopyEdit

class MyThread extends Thread {

public void run() {

System.out.println("Thread running: " + Thread.currentThread().getName());

public class ThreadExample {

public static void main(String[] args) {

MyThread t1 = new MyThread();

t1.start(); // Starts a new thread

Pros

✅ Simple to use
✅ Can directly access Thread methods

Cons

❌ Java doesn’t support multiple inheritance, so extending Thread prevents extending another class

2. Implementing the Runnable Interface


Instead of extending Thread, we implement Runnable and pass it to a Thread object.

Example:

java

CopyEdit

class MyRunnable implements Runnable {

public void run() {

System.out.println("Runnable thread running: " + Thread.currentThread().getName());

public class RunnableExample {

public static void main(String[] args) {

Thread t1 = new Thread(new MyRunnable());

t1.start();

Pros

✅ Allows extending another class


✅ Better separation of concerns

Cons

❌ Requires explicitly creating a Thread object

3. Using Callable and Future (for returning results)

Unlike Runnable, Callable returns a result and can throw checked exceptions. It is executed using
ExecutorService.

Example:

java

CopyEdit

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;
class MyCallable implements Callable<String> {

public String call() throws Exception {

return "Callable executed by " + Thread.currentThread().getName();

public class CallableExample {

public static void main(String[] args) throws Exception {

ExecutorService executor = Executors.newSingleThreadExecutor();

Future<String> future = executor.submit(new MyCallable());

System.out.println(future.get()); // Blocks until result is available

executor.shutdown();

Pros

✅ Returns a result
✅ Supports checked exceptions

Cons

❌ Requires ExecutorService
❌ Uses Future.get(), which can block execution

4. Using ExecutorService (Recommended for Thread Pooling)

Instead of manually creating and managing threads, ExecutorService efficiently handles multiple
threads using a thread pool.

Example:

java

CopyEdit

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;
class MyTask implements Runnable {

public void run() {

System.out.println("Task executed by: " + Thread.currentThread().getName());

public class ExecutorExample {

public static void main(String[] args) {

ExecutorService executor = Executors.newFixedThreadPool(3); // Thread pool of size 3

for (int i = 0; i < 5; i++) {

executor.submit(new MyTask());

executor.shutdown(); // Shut down the executor

Pros

✅ Manages multiple threads efficiently


✅ Avoids manual thread creation overhead
✅ Allows reuse of threads

Cons

❌ Requires proper thread management (shutdown(), handling exceptions)

Which Approach Should You Use?

Method Best For

Extending
Simple tasks, quick prototyping
Thread

Implementing
Recommended for most use cases
Runnable

Using Callable &


When you need a return value or handle exceptions
Future
Method Best For

Using Best for handling multiple threads efficiently


ExecutorService

What is Atomicity?

Atomicity is one of the ACID (Atomicity, Consistency, Isolation, Durability)


properties in database transactions. It ensures that a transaction is all-or-nothing
—either all operations in a transaction are successfully completed, or none of
them are applied.

Key Concept of Atomicity

 If a transaction has multiple operations, either all succeed or all fail.

 If any part of the transaction fails, the database rolls back to its previous
state.

Example of Atomicity

Example 1: Bank Transfer

Imagine a money transfer from Account A to Account B:

1. Debit ₹1000 from Account A

2. Credit ₹1000 to Account B

✅ If both steps succeed → Transaction is committed.


❌ If one step fails (e.g., server crash, network issue) → Transaction is rolled back.

SQL Example

sql

CopyEdit

START TRANSACTION;

UPDATE accounts SET balance = balance - 1000 WHERE account_id = 1; -- Debit


₹1000

UPDATE accounts SET balance = balance + 1000 WHERE account_id = 2; -- Credit


₹1000

COMMIT; -- Save changes

If any update fails, we ROLLBACK to prevent an inconsistent state:


Method Best For

sql

CopyEdit

ROLLBACK; -- Undo all changes

Atomicity in REST APIs

In REST APIs, atomicity ensures that a request completes fully or fails without
partial updates.

Example: User Registration API

Steps in registering a user:

1. Insert user details in the database

2. Send a verification email

If step 2 fails, step 1 must be rolled back to maintain atomicity.

Spring Boot Example (Transactional Annotation)

In Java (Spring Boot), we use @Transactional to ensure atomicity:

java

CopyEdit

@Service

public class UserService {

@Autowired

private UserRepository userRepository;

@Transactional

public void registerUser(User user) {

userRepository.save(user); // Step 1: Save user

sendVerificationEmail(user); // Step 2: Send email

If sendVerificationEmail(user) fails, the userRepository.save(user) is automatically


rolled back.

Why is Atomicity Important?


Method Best For

✅ Prevents Partial Updates – Avoids data corruption.


✅ Ensures Data Integrity – Transactions remain consistent.
✅ Improves Reliability – Database is never left in an incomplete state.

Would you like an example of atomicity in distributed transactions (e.g., using


Kafka or two-phase commit)? 🚀

4o

You said:

atomicity integer?

ChatGPT said:

What is Atomicity in the Context of Integers?

When discussing atomicity with integers, it usually refers to atomic operations on


integer variables in multithreaded programming. An atomic operation ensures
that an integer update (e.g., increment, decrement) is performed without
interruption by other threads.

Why is Atomicity Important for Integers?

In multithreading, if multiple threads modify a shared integer without atomicity,


race conditions may occur, leading to incorrect values.

Example of Non-Atomic Integer Increment (Race Condition)

java

CopyEdit

class Counter {

int count = 0;

void increment() {

count++; // Not atomic (read-modify-write cycle)

 If two threads execute count++ simultaneously:

1. One thread reads count = 5, another also reads count = 5

2. Both increment to 6, but one overwrites the other

3. The expected result (7) is lost


Method Best For

💥 This is a race condition!

How to Ensure Atomicity for Integers?

1. Using synchronized Block (Ensures only one thread updates at a time)

java

CopyEdit

class Counter {

int count = 0;

synchronized void increment() {

count++;

✅ Ensures atomicity but can cause performance overhead due to locking.

2. Using AtomicInteger (Preferred for Performance)

Java provides AtomicInteger, which guarantees atomic updates without using


locks.

java

CopyEdit

import java.util.concurrent.atomic.AtomicInteger;

class Counter {

AtomicInteger count = new AtomicInteger(0);

void increment() {

count.incrementAndGet(); // Atomic operation

✅ Efficient & thread-safe


✅ No need for explicit synchronization
Method Best For

Atomic Integer Operations in Java

Method Description

Atomically increments and returns the new


incrementAndGet()
value

Atomically decrements and returns the new


decrementAndGet()
value

Atomically adds delta and returns the new


addAndGet(int delta)
value

compareAndSet(int expected, int


Updates value only if it matches expected
update)

Example: Compare-and-Swap (CAS)

java

CopyEdit

AtomicInteger atomicInt = new AtomicInteger(10);

boolean updated = atomicInt.compareAndSet(10, 20); // If 10, update to 20

✅ Ensures safe concurrent updates without using locks.

Summary

 Atomicity ensures integer updates are done safely in multithreading.

 Non-atomic updates (count++) can lead to race conditions.

 Use synchronized (locks) or AtomicInteger (lock-free, efficient).

Difference Between ReentrantLock and synchronized in Java

Both ReentrantLock and synchronized are used for thread synchronization in Java,
but they have key differences in flexibility, performance, and control.

1. Overview

Feature synchronized ReentrantLock

Type Built-in Java Explicit Lock class


Method Best For

Feature synchronized ReentrantLock

keyword (java.util.concurrent.locks.ReentrantLock)

Flexibility Less flexible More flexible

No fairness
Fairness Supports fairness (First-Come-First-Serve)
control

Try-Lock
Not possible Possible (tryLock())
Mechanism

Interruptible
Not possible Possible (lockInterruptibly())
Locking

Condition Supports Condition for advanced


No support
Variables synchronization

Less overhead in
Performance Better for complex, high-concurrency scenarios
simple cases

2. synchronized - Built-in Lock Mechanism

The synchronized keyword provides automatic locking on objects or methods.

Example: Synchronized Method

java

CopyEdit

class Counter {

private int count = 0;

public synchronized void increment() { // Lock is acquired on this instance

count++;

Example: Synchronized Block

java

CopyEdit

class Counter {

private int count = 0;


Method Best For

private final Object lock = new Object();

public void increment() {

synchronized (lock) { // Lock is acquired on 'lock' object

count++;

✅ Advantages of synchronized
✔ Simple and easy to use
✔ Automatically releases lock after execution

❌ Limitations

 Cannot attempt non-blocking locks (tryLock()).

 No explicit lock control (no fairness or interrupt handling).

3. ReentrantLock - More Flexible Locking

ReentrantLock is a more advanced, flexible locking mechanism from


java.util.concurrent.locks.

Example: Using ReentrantLock

java

CopyEdit

import java.util.concurrent.locks.ReentrantLock;

class Counter {

private int count = 0;

private final ReentrantLock lock = new ReentrantLock();

public void increment() {

lock.lock(); // Acquire lock

try {
Method Best For

count++;

} finally {

lock.unlock(); // Always release lock

✅ Advantages of ReentrantLock
✔ Try-Lock Mechanism → Avoids deadlocks
✔ Interruptible Locks → Threads can be interrupted while waiting
✔ Supports Fairness → Ensures first-come-first-serve locking
✔ Multiple Conditions → More fine-grained synchronization

❌ Limitations

 Must explicitly release the lock (unlock()).

 More complex than synchronized.

4. Key Differences with Examples

🔹 1. Try-Lock Mechanism (tryLock())

With synchronized, a thread waits indefinitely for a lock.


With ReentrantLock, a thread can try to acquire a lock without blocking.

Example: Using tryLock() to Avoid Blocking

java

CopyEdit

if (lock.tryLock()) { // If lock is available, acquire it

try {

// Critical section

} finally {

lock.unlock(); // Release lock

} else {

System.out.println("Lock not available, do something else!");

}
Method Best For

✅ Prevents deadlocks by not blocking if the lock is unavailable.

🔹 2. Interruptible Locking (lockInterruptibly())

With synchronized, a thread cannot be interrupted while waiting for a lock.


With ReentrantLock, a waiting thread can be interrupted.

Example: Using lockInterruptibly()

java

CopyEdit

try {

lock.lockInterruptibly(); // Allows interruption

// Critical section

} catch (InterruptedException e) {

System.out.println("Thread interrupted while waiting for lock.");

} finally {

lock.unlock();

✅ Useful when handling timeouts or thread cancellation.

🔹 3. Fairness Policy (First-Come-First-Serve)

 synchronized does not guarantee fairness.

 ReentrantLock supports fairness when created with true.

Example: Fair Lock

java

CopyEdit

ReentrantLock fairLock = new ReentrantLock(true); // Fair lock (FIFO order)

✅ Ensures that threads get locks in the order they requested them.

5. When to Use What?

Use synchronized when... Use ReentrantLock when...

Simplicity is preferred. Advanced lock control is needed.


Method Best For

Use synchronized when... Use ReentrantLock when...

There’s no need for tryLock() or


You need tryLock() to avoid blocking.
interruptible locks.

First-Come-First-Serve fairness is
No fairness is required.
needed.

You need advanced Condition


No need for multiple condition variables.
objects.

6. Conclusion

 For simple synchronization → synchronized is best.

 For fine-grained control, fairness, or interruptible locks → ReentrantLock


is better

Thread States in Java (Lifecycle of a Thread)

In Java, a thread can exist in six different states as defined in the Thread.State
enumeration.

1. New (NEW)

Definition: A thread that has been created but has not started yet.
Example:

java

CopyEdit

Thread t = new Thread(() -> System.out.println("Hello"));

The thread t is in the NEW state because start() has not been called.
Method Best For

2. Runnable (RUNNABLE)

Definition: A thread that is ready to run and waiting for CPU time.
Example:

java

CopyEdit

t.start(); // Now thread moves to RUNNABLE state

The thread is not necessarily running; it depends on the OS thread scheduler.

3. Blocked (BLOCKED)

Definition: A thread is waiting to acquire a lock (due to synchronized).


Example:

java

CopyEdit

class SharedResource {

synchronized void method() {

System.out.println(Thread.currentThread().getName() + " is running");

SharedResource resource = new SharedResource();

Thread t1 = new Thread(() -> resource.method());

Thread t2 = new Thread(() -> resource.method());

t1.start();

t2.start(); // If t1 has the lock, t2 moves to BLOCKED state.

✅ Occurs when one thread has a lock, and others are waiting for it.

4. Waiting (WAITING)

Definition: A thread is waiting indefinitely for another thread to notify it.


Example:
Method Best For

java

CopyEdit

class Example {

synchronized void waitForSignal() throws InterruptedException {

wait(); // Moves thread to WAITING state

synchronized void sendSignal() {

notify(); // Wakes up a waiting thread

✅ Must be notified using notify() or notifyAll().

5. Timed Waiting (TIMED_WAITING)

Definition: A thread is waiting for a specific time period (e.g., sleep(), join(),
wait(timeout)).
Example:

java

CopyEdit

Thread.sleep(2000); // Thread enters TIMED_WAITING for 2 seconds

✅ Automatically moves back to RUNNABLE when time expires.

6. Terminated (TERMINATED)

Definition: A thread has finished execution or was stopped unexpectedly.


Example:

java

CopyEdit

Thread t = new Thread(() -> System.out.println("Done!"));

t.start();

t.join(); // Ensures thread completes execution


Method Best For

System.out.println(t.getState()); // TERMINATED

Thread Lifecycle Diagram

sql

CopyEdit

NEW → RUNNABLE → BLOCKED / WAITING / TIMED_WAITING → TERMINATED

Summary of Java Thread States

State Occurs When... How to Move Out?

NEW Thread is created but not started. Call start().

RUNNABLE Ready to run, waiting for CPU time. OS scheduler selects it.

BLOCKED Waiting for a lock (synchronized). Lock is released.

notify() or join()
WAITING Waiting indefinitely (wait(), join()).
completes.

Waiting for a fixed time (sleep(),


TIMED_WAITING Time expires.
wait(timeout)).

TERMINATED Thread has finished execution. Cannot transition out.

Example: Get Current Thread State

java

CopyEdit

System.out.println(Thread.currentThread().getState());

Difference Between Thread.yield(), Thread.sleep(), and Thread.join() in Java

All three methods (yield(), sleep(), and join()) are used to control thread execution
but serve different purposes.

1. Thread.yield()

📌 Purpose: Suggests the thread scheduler to pause the current thread and allow
other threads to execute.
📌 Does it release CPU? ✅ Yes (but it's not guaranteed).
📌 Does it release locks? ❌ No.
Method Best For

Example

java

CopyEdit

class YieldExample extends Thread {

public void run() {

for (int i = 0; i < 5; i++) {

System.out.println(Thread.currentThread().getName() + " is running.");

Thread.yield(); // Suggest CPU to give other threads a chance

public class Main {

public static void main(String[] args) {

YieldExample t1 = new YieldExample();

YieldExample t2 = new YieldExample();

t1.start();

t2.start();

✅ Thread.yield() does not guarantee that another thread will run immediately. It
just hints the scheduler.

2. Thread.sleep(time)

📌 Purpose: Pauses the current thread for a specified time.


📌 Does it release CPU? ✅ Yes.
📌 Does it release locks? ❌ No.

Example

java

CopyEdit
Method Best For

class SleepExample extends Thread {

public void run() {

for (int i = 1; i <= 3; i++) {

try {

System.out.println(Thread.currentThread().getName() + " is sleeping for 2


seconds.");

Thread.sleep(2000); // Pause for 2 seconds

} catch (InterruptedException e) {

e.printStackTrace();

public class Main {

public static void main(String[] args) {

SleepExample t1 = new SleepExample();

t1.start();

✅ Thread.sleep(2000) pauses execution for 2 seconds, but the thread remains in


the TIMED_WAITING state.

3. Thread.join()

📌 Purpose: Makes the current thread wait until another thread finishes execution.
📌 Does it release CPU? ✅ Yes.
📌 Does it release locks? ❌ No.

Example

java

CopyEdit

class JoinExample extends Thread {


Method Best For

public void run() {

for (int i = 1; i <= 3; i++) {

System.out.println(Thread.currentThread().getName() + " is running.");

try {

Thread.sleep(1000); // Simulating work

} catch (InterruptedException e) {

e.printStackTrace();

public class Main {

public static void main(String[] args) throws InterruptedException {

JoinExample t1 = new JoinExample();

t1.start();

t1.join(); // Main thread waits for t1 to finish

System.out.println("Main thread continues after t1 finishes.");

✅ t1.join(); ensures that the main thread waits until t1 finishes.

Summary of Differences

Releases Releases
Method Purpose Example Use Case
CPU? Locks?

Suggests thread Useful when a thread has


scheduler to switch completed its important
yield() ✅ Yes ❌ No
execution to work but doesn't need CPU
another thread immediately.
Method Best For

Releases Releases
Method Purpose Example Use Case
CPU? Locks?

Pauses thread Useful for rate limiting,


sleep(time) execution for a ✅ Yes ❌ No waiting before retrying an
specified time operation.

Makes a thread Useful when one thread


wait until another must complete before
join() thread completes ✅ Yes ❌ No another continues (e.g.,
waiting for a background
task).

Types of Thread Pools in Java (ExecutorService)

Java provides different types of thread pools in the java.util.concurrent.Executors


class to manage multiple threads efficiently.

1. Fixed Thread Pool (newFixedThreadPool(n))

📌 Creates a pool of a fixed number of threads (n).


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

Example

java

CopyEdit

import java.util.concurrent.*;

public class FixedThreadPoolExample {

public static void main(String[] args) {

ExecutorService executor = Executors.newFixedThreadPool(3); // Pool with 3


threads

for (int i = 1; i <= 5; i++) {

final int task = i;

executor.execute(() -> System.out.println("Executing Task " + task + " by " +


Method Best For

Thread.currentThread().getName()));

executor.shutdown(); // Shutdown after task completion

✅ Use Case: Suitable for applications with a fixed number of tasks, like web
servers.

2. Cached Thread Pool (newCachedThreadPool())

📌 Creates new threads as needed and reuses idle ones.


📌 If no threads are available, new ones are created.
📌 Threads are removed if idle for 60 seconds.

Example

java

CopyEdit

ExecutorService executor = Executors.newCachedThreadPool();

for (int i = 1; i <= 5; i++) {

final int task = i;

executor.execute(() -> System.out.println("Executing Task " + task + " by " +


Thread.currentThread().getName()));

executor.shutdown();

✅ Use Case: Good for applications with many short-lived tasks, like handling many
small API requests.

3. Single Thread Pool (newSingleThreadExecutor())

📌 Creates a pool with only one thread.


📌 Tasks execute sequentially (one at a time).

Example
Method Best For

java

CopyEdit

ExecutorService executor = Executors.newSingleThreadExecutor();

for (int i = 1; i <= 3; i++) {

final int task = i;

executor.execute(() -> System.out.println("Executing Task " + task + " by " +


Thread.currentThread().getName()));

executor.shutdown();

✅ Use Case: Ensures task execution order (e.g., writing logs sequentially).

4. Scheduled Thread Pool (newScheduledThreadPool(n))

📌 Executes tasks at a fixed delay or periodically.

Example: Run Task After a Delay

java

CopyEdit

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

scheduler.schedule(() -> System.out.println("Task executed after 3 seconds"), 3,


TimeUnit.SECONDS);

scheduler.shutdown();

Example: Run Task Periodically

java

CopyEdit

scheduler.scheduleAtFixedRate(() -> System.out.println("Periodic Task"), 1, 2,


TimeUnit.SECONDS);

✅ Use Case: Best for scheduled tasks, like cron jobs or auto-backups.
Method Best For

5. Work-Stealing Pool (newWorkStealingPool(n)) (Java 8+)

📌 Creates a pool of n threads using a ForkJoinPool.


📌 Automatically manages task distribution across multiple CPU cores.
📌 Efficient for parallel processing.

Example

java

CopyEdit

ExecutorService executor = Executors.newWorkStealingPool();

for (int i = 1; i <= 5; i++) {

final int task = i;

executor.execute(() -> System.out.println("Executing Task " + task + " by " +


Thread.currentThread().getName()));

executor.shutdown();

✅ Use Case: Best for CPU-intensive tasks, like image processing or data analysis.

Summary of Thread Pools

Thread Pool Description Best Use Case

Fixed Thread A fixed number of threads Best for a known, constant


Pool (n). workload (e.g., web servers).

Cached Thread Creates new threads as Best for handling many small, short-
Pool needed, reuses idle ones. lived tasks (e.g., API requests).

Single Thread Best when tasks must be executed


Single-threaded execution.
Pool in order (e.g., logging).

Scheduled Runs tasks after a delay or at Best for periodic tasks (e.g.,
Thread Pool fixed intervals. backups, cron jobs).

Work-Stealing Uses ForkJoinPool for Best for CPU-intensive tasks (e.g.,


Pool parallel processing. image processing).

How to Handle Deadlock in Java?


Method Best For

A deadlock occurs when two or more threads are waiting for each other to release
locks, causing an infinite wait. Here are different strategies to prevent and resolve
deadlocks.

1. Lock Ordering (Avoid Circular Wait) ✅

📌 Ensure that all threads acquire locks in the same order.

Example Without Lock Ordering (Deadlock Scenario) ❌

java

CopyEdit

class A {

synchronized void methodA(B b) {

System.out.println(Thread.currentThread().getName() + " locked A, waiting for


B");

synchronized (b) {

System.out.println(Thread.currentThread().getName() + " locked B");

class B {

synchronized void methodB(A a) {

System.out.println(Thread.currentThread().getName() + " locked B, waiting for


A");

synchronized (a) {

System.out.println(Thread.currentThread().getName() + " locked A");

🚨 Issue:

 Thread-1 locks A and waits for B.

 Thread-2 locks B and waits for A.


Method Best For

 Deadlock occurs because both threads are waiting for each other.

✅ Corrected Version (Using Lock Ordering)

java

CopyEdit

class A {

synchronized void methodA(B b) {

synchronized (this) { // Lock A first

System.out.println(Thread.currentThread().getName() + " locked A");

synchronized (b) { // Then lock B

System.out.println(Thread.currentThread().getName() + " locked B");

✅ Fix: Always acquire locks in the same order (A → B).

2. Try-Lock with Timeout (Using ReentrantLock) ✅

📌 Instead of blocking forever, try acquiring a lock for a limited time.

Example

java

CopyEdit

import java.util.concurrent.locks.*;

class DeadlockAvoidance {

private final Lock lock1 = new ReentrantLock();

private final Lock lock2 = new ReentrantLock();

void process() {
Method Best For

try {

if (lock1.tryLock() && lock2.tryLock()) {

try {

System.out.println(Thread.currentThread().getName() + " acquired both


locks");

} finally {

lock2.unlock();

lock1.unlock();

} else {

System.out.println(Thread.currentThread().getName() + " could not


acquire locks, avoiding deadlock");

} finally {

if (lock1.isHeldByCurrentThread()) lock1.unlock();

if (lock2.isHeldByCurrentThread()) lock2.unlock();

public class Main {

public static void main(String[] args) {

DeadlockAvoidance obj = new DeadlockAvoidance();

new Thread(obj::process).start();

new Thread(obj::process).start();

✅ Fix: tryLock() prevents deadlock by failing gracefully if locks are unavailable.

3. Use a Single Lock Instead of Multiple Locks ✅

📌 Avoid using multiple locks if not necessary.


Method Best For

Example

java

CopyEdit

class SingleLockExample {

private final Object lock = new Object();

void process() {

synchronized (lock) {

System.out.println(Thread.currentThread().getName() + " acquired lock");

✅ Fix: Using a single lock prevents cyclic waiting.

4. Detect Deadlocks Using ThreadMXBean ✅

📌 Java provides ThreadMXBean to detect deadlocks at runtime.

Example

java

CopyEdit

import java.lang.management.*;

public class DeadlockDetector {

public static void main(String[] args) {

ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();

long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();

if (deadlockedThreads != null) {

System.out.println("Deadlock detected in threads: " +


deadlockedThreads.length);

} else {
Method Best For

System.out.println("No deadlock detected.");

✅ Fix: Monitor and log deadlocks for debugging.

5. Break Deadlocks by Interrupting a Thread ✅

📌 Interrupt a thread if it holds a lock for too long.

Example

java

CopyEdit

class Task implements Runnable {

private final Object lock1;

private final Object lock2;

Task(Object lock1, Object lock2) {

this.lock1 = lock1;

this.lock2 = lock2;

public void run() {

try {

synchronized (lock1) {

Thread.sleep(50);

synchronized (lock2) {

System.out.println(Thread.currentThread().getName() + " acquired


locks");

} catch (InterruptedException e) {
Method Best For

System.out.println(Thread.currentThread().getName() + " interrupted to


prevent deadlock");

public class Main {

public static void main(String[] args) {

Object lockA = new Object();

Object lockB = new Object();

Thread t1 = new Thread(new Task(lockA, lockB));

Thread t2 = new Thread(new Task(lockB, lockA));

t1.start();

t2.start();

try {

Thread.sleep(100); // If deadlock happens, interrupt one thread

t1.interrupt();

} catch (InterruptedException e) {

e.printStackTrace();

✅ Fix: Interrupt the thread if it takes too long to acquire a lock.

Summary of Deadlock Prevention Strategies

Method How It Works Best Use Case

Lock Always acquire locks in a consistent order (e.g., Most effective


Method Best For

Method How It Works Best Use Case

when multiple locks


Ordering A → B)
are needed

Try-Lock with Use lock.tryLock(timeout) to fail gracefully if a Best for preventing


Timeout lock is unavailable long waits

Best when only one


Use a Single
Avoid multiple locks if possible shared resource is
Lock
involved

Detect Use ThreadMXBean.findDeadlockedThreads() Best for debugging


Deadlocks to monitor and debug in production

Interrupt Interrupt a thread if it takes too long to acquire Best for highly
Threads a lock responsive systems

You might also like