0% found this document useful (0 votes)
3 views

Deadlock in Java Multithreading and Prevention Strategies

Deadlock in Java multithreading occurs when two or more threads are blocked indefinitely, waiting for each other to release resources. Prevention strategies include lock ordering, using tryLock, implementing timeouts, and utilizing a single lock to avoid circular waits. The choice of strategy depends on specific application requirements.

Uploaded by

anvisuri05
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)
3 views

Deadlock in Java Multithreading and Prevention Strategies

Deadlock in Java multithreading occurs when two or more threads are blocked indefinitely, waiting for each other to release resources. Prevention strategies include lock ordering, using tryLock, implementing timeouts, and utilizing a single lock to avoid circular waits. The choice of strategy depends on specific application requirements.

Uploaded by

anvisuri05
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/ 7

Deadlock in Java Multithreading and Prevention Strategies

1. What is Deadlock?

A deadlock is a situation in Java multithreading where two or more threads are blocked forever,
waiting for each other to release a resource. This happens when multiple threads hold some shared
resources and wait indefinitely for other resources held by other threads.

Example of Deadlock Scenario

• Thread A locks Resource 1 and waits for Resource 2.

• Thread B locks Resource 2 and waits for Resource 1.

• Both threads wait indefinitely, causing a deadlock.

2. How Does Deadlock Occur?

Deadlock occurs when the following four conditions hold simultaneously:

1. Mutual Exclusion → A resource can only be accessed by one thread at a time.

2. Hold and Wait → A thread holds a resource and waits for another.

3. No Preemption → A resource cannot be forcibly taken away.

4. Circular Wait → A cycle of dependencies is created between threads.

3. Example of Deadlock in Java

class Resource {

void methodA(Resource otherResource) {

synchronized (this) {

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

try { Thread.sleep(100); } catch (InterruptedException e) {}

synchronized (otherResource) {

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

public class DeadlockExample {

public static void main(String[] args) {


Resource resource1 = new Resource();

Resource resource2 = new Resource();

Thread thread1 = new Thread(() -> resource1.methodA(resource2), "Thread-1");

Thread thread2 = new Thread(() -> resource2.methodA(resource1), "Thread-2");

thread1.start();

thread2.start();

Output (Deadlock Situation)

Thread-1 locked Resource@1a2b3c

Thread-2 locked Resource@4d5e6f

(Threads are stuck waiting forever.)

4. How to Prevent Deadlock in Java?

1. Avoid Nested Locks (Use Lock Ordering)

Always acquire locks in a fixed, consistent order to prevent circular waiting.

Example (Corrected Code with Lock Ordering)

class SafeResource {

void methodA(SafeResource otherResource) {

synchronized (this) {

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

synchronized (otherResource) { // Always lock in the same order

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

Ensures that Thread-1 and Thread-2 acquire locks in the same sequence, preventing circular
wait.
2. Use Try-Lock Instead of Synchronized (Avoid Waiting Forever)

Use tryLock() from ReentrantLock instead of synchronized, so threads do not wait indefinitely.

Example Using tryLock()

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

class ResourceSafe {

private final Lock lock1 = new ReentrantLock();

private final Lock lock2 = new ReentrantLock();

void safeMethod() {

while (true) {

if (lock1.tryLock()) {

try {

if (lock2.tryLock()) {

try {

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

break;

} finally { lock2.unlock(); }

} finally { lock1.unlock(); }

// Retry after some time

try { Thread.sleep(50); } catch (InterruptedException ignored) {}

public class TryLockExample {

public static void main(String[] args) {


ResourceSafe resource = new ResourceSafe();

Thread t1 = new Thread(resource::safeMethod, "Thread-1");

Thread t2 = new Thread(resource::safeMethod, "Thread-2");

t1.start();

t2.start();

If a thread cannot acquire both locks, it releases the first lock and retries, avoiding deadlock.

3. Use a Timeout to Avoid Infinite Waiting

If a thread cannot acquire a lock within a set time, it backs off and retries later.

Example Using tryLock(timeout)

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

import java.util.concurrent.TimeUnit;

class TimeoutResource {

private final Lock lock1 = new ReentrantLock();

private final Lock lock2 = new ReentrantLock();

void safeMethod() {

try {

if (lock1.tryLock(100, TimeUnit.MILLISECONDS)) {

try {

if (lock2.tryLock(100, TimeUnit.MILLISECONDS)) {

try {

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

} finally { lock2.unlock(); }

} finally { lock1.unlock(); }
} else {

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


retrying...");

} catch (InterruptedException ignored) {}

public class TimeoutExample {

public static void main(String[] args) {

TimeoutResource resource = new TimeoutResource();

Thread t1 = new Thread(resource::safeMethod, "Thread-1");

Thread t2 = new Thread(resource::safeMethod, "Thread-2");

t1.start();

t2.start();

If a thread cannot acquire both locks within 100ms, it retries later, preventing deadlock.

4. Use a Single Lock Instead of Multiple Locks

If possible, use one lock for all resources instead of multiple locks.

Example Using a Single Lock

import java.util.concurrent.locks.ReentrantLock;

class SingleLockResource {

private final ReentrantLock lock = new ReentrantLock();

void method() {

lock.lock();

try {
System.out.println(Thread.currentThread().getName() + " is executing.");

} finally {

lock.unlock();

public class SingleLockExample {

public static void main(String[] args) {

SingleLockResource resource = new SingleLockResource();

Thread t1 = new Thread(resource::method, "Thread-1");

Thread t2 = new Thread(resource::method, "Thread-2");

t1.start();

t2.start();

Since both threads use the same lock, deadlock cannot occur.

5. Summary of Deadlock Prevention Strategies

Strategy Description Effectiveness

Lock Ordering Always acquire locks in a fixed order Highly effective

Acquire locks only if available, avoid


Try-Lock (tryLock()) Prevents indefinite waiting
waiting

Timeout on Locks Use tryLock(timeout) to retry later Avoids long waits

Single Lock
Use one lock instead of multiple locks Prevents circular wait
Approach

Do not hold one lock while waiting for Reduces risk but not always
Avoid Nested Locks
another possible

6. Conclusion
• Deadlock is a critical issue in Java multithreading that occurs when threads wait indefinitely
for each other.

• Prevention strategies like lock ordering, tryLock, timeouts, and single locks help avoid
deadlocks.

• Choosing the right strategy depends on the application requirements.

Would you like a real-world example, such as preventing deadlocks in a banking transaction
system?

You might also like