Table of Contents
In a multithreading environment, there are many chances for a Java deadlock situation to occur. A deadlock occurs when two threads wait for each other infinitely and is blocked forever. The threads are blocked since it requires the same lock. For example, consider two threads T1 and T2. T1 acquires lock1 and T2 acquires lock2. Now during execution, T1 wants to acquire lock2 and T2 wants to acquire lock1. Since both the threads are waiting for each other to release the lock, it results in a java deadlock condition. Both the threads acquire the locks by using the synchronized keyword.
To know more about Java, Download Entri App!
What is deadlock in Java?
In the thread, each object has a lock. To acquire a lock, Java provides synchronization to lock a method or code block. It allows that at a time only one thread can access that method.
Nevertheless, if a thread wants to execute a synchronized method it first tries to acquire a lock. It is possible that another thread has already acquired that lock then the thread (that wants to acquire the lock) will have to wait until the previous thread does not release the lock.
Let’s understand it through an example.
Example
Suppose, there are two threads A and B. The thread A and B acquired the lock of Object-A and Object-B, respectively. Assume that thread A executing method A and wants to acquire the lock on Object-B, while thread B is already acquired a lock on Object-B.
On the other hand, thread B also tries to acquire a lock on Object-A, while thread A is acquired a lock on Object-A. In such a situation both threads will not complete their execution and wait for releasing the lock. The situation is known as, deadlock.
publicvoid methodA()
{
//…
synchronized(lockA)
{
//…
synchronized(lockB)
{
//…
}
}
}
publicvoid methodB()
{
//…
synchronized(lockB)
{
//…
synchronized(lockA)
{
//…
}
}
}
To know more about Java, Download Entri App!
How to detect deadlock in Java?
There are following ways to detect a deadlock:
- First, we look and understand the code if we found nested synchronized block or trying to get a lock on a different object or calling a synchronized method from other synchronized method, these reason leads to a deadlock situation.
- Another way to detect deadlock is to use the io It allows us to upload a thread dump and analyze it.
- We can also use jConsoleor VisualVM to detect deadlock. It shows us which threads are getting locked and on which object.
Consider a situation when two bank accounts trying to transfer money to each other at the same time. It means that one account is debited and another account is credited, and vice-versa. Let’s implement the situation in a Java program.
In the following example, we can easily detect a deadlock. Because two threads are sending money to each other at the same time that leads to a deadlock situation.
Account.java
classAccount
{
doublebalance;
void deposit(double amount)
{
balance += amount;
}
void withdraw(double amount)
{
balance -= amount;
}
void transfer(Account from, Account to, double amount){
sync(from);
sync(to);
from.withdraw(amount);
deposit(amount);
release(to);
release(from);
}
}
In the above example, there are two threads that are attempting to transfer money to each other at the same time. It creates a deadlock situation because the threads try to acquire the lock in the reverse order.
How to avoid deadlock in Java?
Although it is not possible to avoid deadlock condition but we can avoid it by using the following ways:
- Avoid Unnecessary Locks:We should use locks only for those members on which it is required. Unnecessary use of locks leads to a deadlock situation. We recommend you to use a lock-free data structure. If possible, keep your code free form locks. For example, instead of using synchronized ArrayList use the ConcurrentLinkedQueue.
- Avoid Nested Locks:Another way to avoid deadlock is to avoid giving a lock to multiple threads if we have already provided a lock to one thread. Since we must avoid allocating a lock to multiple threads.
- Using Thread.join() Method:You can get a deadlock if two threads are waiting for each other to finish indefinitely using thread join. If your thread has to wait for another thread to finish, it’s always best to use join with the maximum time you want to wait for the thread to finish.
- Use Lock Ordering:Always assign a numeric value to each lock. Before acquiring the lock with a higher numeric value, acquire the locks with a lower numeric value.
- Lock Time-out:We can also specify the time for a thread to acquire a lock. If a thread does not acquire a lock, the thread must wait for a specific time before retrying to acquire a lock.
Let’s understand it through an example.
AvoidDeadlockExamplet.java
publicclass AvoidDeadlockExample
{
publicstatic void main(String[] args) throws InterruptedException
{
//creating object of the Object class
Object object1 = new Object();
Object object2 = newObject();
Object object3 = new Object();
//creating constructor of the Thread class and passing SynchroniseThread object as a parameter
Thread thread1 = new Thread(new SynchroniseThread(object1, object2), “thread1”);
Thread thread2 = newThread(new SynchroniseThread(object2, object3), “thread2”);
//executing thread1
start();
//the sleep() method suspends the execution of the current thread (thread1) for the specific period
sleep(2000);
//executing thread2
start();
//suspends the execution of the current thread (thread2) for the specific period
sleep(2000);
}}
class SynchroniseThread implements Runnable
{
private Object object1;
privateObject object2;
public SynchroniseThread(Object o1, Object o2)
{
this.object1=o1;
this.object2=o2;
}
//overriding run() method of the Thread class
@Override
//it allows two threads are running concurrently
public void run()
{
//getteing the current thread name
String name = Thread.currentThread().getName();
System.out.println(name + ” acquire lock on ” + object1);
//Synchronized() method is used to lock an object for any shared resource. When a thread invokes the synchronized() method,
//it automatically acquires the lock for that object and releases it when the thread completes its task.
synchronized(object1)
{
out.println(name + ” acquired lock on “+ object1);
//calling work() method
work();
}
out.println(name + ” released lock of “+ object1);
System.out.println(name + ” acquire lock on ” + object2);
synchronized(object2)
{
out.println(name + ” acquire lock on “+ object2);
work();
}
System.out.println(name + ” released lock of ” + object2);
out.println(name + ” execution is completed.”);
}
privatevoid work()
{
try
{
//the sleep() method suspends the execution of the current thread for 5 seconds
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
Output:
We recommend you that if you are dealing with multiple locks, always acquire the locks with lower numerical value before acquiring the locks with a higher numeric value.
To know more about Java, Download Entri App!
Why is it important to choose Entri?
- Excellent online platform for all the Competitive Exams.
- Provides updated materials created by the Entri Experts.
- Entri provides a best platform with full- length mock tests including previous year question papers.
- You can download the app for free and join the required classes.
- Entri wishes you all the best for your examinations and future endeavours.
“YOU DON’T HAVE TO BE GREAT TO START, BUT YOU HAVE TO START TO BE GREAT.”