What Is Deadlock In Java?
Deadlock in java is a condition which occurs when
two or more threads get blocked waiting for each other for an infinite period
of time to release the resources (Locks) they hold. Deadlock is the common
problem in multi-threaded programming which can completely stops the execution
of an application. So, extra care needs to be taken while writing the multi-threaded
programs so that deadlock never occurs.
Let’s look at one simple example of deadlock
condition.
Class Shared
{
synchronized void methodOne(Shared s)
{
Thread
t = Thread.currentThread();
System.out.println(t.getName()+"is executing methodOne...");
System.out.println(t.getName()+"is calling methodTwo...");
s.methodTwo(this);
System.out.println(t.getName()+"is finished executing
methodOne...");
}
synchronized void methodTwo(Shared s)
{
Thread
t = Thread.currentThread();
System.out.println(t.getName()+"is executing methodTwo...");
System.out.println(t.getName()+"is calling methodOne...");
s.methodOne(this);
System.out.println(t.getName()+"is finished executing
methodTwo...");
}
}
public class DeadLockInJava
{
public
static void main(String[] args)
{
final
Shared s1 = new Shared();
final
Shared s2 = new Shared();
Thread
t1 = new Thread()
{
public void run()
{
s1.methodOne(s2);
}
};
Thread
t2 = new Thread()
{
@Override
public void run()
{
s2.methodTwo(s1);
}
};
t1.start();
t2.start();
}
}
In the above multi-threaded program, thread t1 and t2 are
concurrent threads i.e. they are executing their task simultaneously. There are
two Shared class objects, s1 and s2, which are
shared by both the threads. Shared class has two synchronized methods, methodOne() and methodTwo().
That means, only one thread can execute these methods at a given time.
First, thread t1 enters the methodOne() of s1 object
by acquiring the object lock of s1. At the same time, thread t2 also
enters the methodTwo() of s2 object by
acquiring the object lock of s2. methodOne() of s1object,
currently executing by thread t1, calls methodTwo() of s2 object
from it’s body. So, thread t1 tries to acquire the object lock
of s2 object. But object lock of s2 object is
already acquired by thread t2. So, thread t1waits for
thread t2 to release the object lock of s2 object.
At the same time, thread t2 is also
executing methodTwo() of s2 object. methodTwo() of s2 object
also makes a call to methodOne() of s1 object.
So, thread t2 tries to acquire the object lock of s1 object.
But, it is already acquired by thread t1. So, thread t2 also
waits for thread t1 to release the object lock of s1 object.
Thus, both the threads wait for each other to
release the object locks they own. They wait for infinite period of time to get
the object locks owned by opposite threads. This condition of threads waiting
forever is called Deadlock.
Deadlock is a
dangerous condition, if it happens, it will bring the whole application to
complete halt. So, extra care needs to be taken to avoid the deadlock.
Followings are some tips that can be used to avoid the deadlock in java.
- Try to avoid
nested synchronized blocks.
A nested synchronized
block makes a thread to acquire another lock while it is already holding
one lock. This may create the deadlock if another thread wants the same
lock which is currently held by this thread.
synchronized
(Lock A)
{
//Some statements
synchronized (Lock B)
{
//Try to avoid this block
}
}
- Lock Ordering :
If
you needed nested synchronized blocks at any cost, then make sure that threads
acquire the needed locks in some predefined order. For example, if there are
three threads t1, t2 and t3 running concurrently and they needed locks A, B and
C in the following manner,
Thread
t1 :
Lock A
Lock B
Thread
t2 :
Lock A
Lock C
Thread
t3 :
Lock A
Lock B
Lock C
In
the above scenario, t1 needs A and B locks, t2 needs A and C locks and t3 needs
A, B and C locks. If you define an order to acquire the locks like, Lock A must
be acquired before Lock B and Lock B must be acquired before Lock c, then
deadlock never occurs in the above case.
If
you define such lock ordering, then thread t2 never acquire lock C and t3 never
acquire lock B and lock C until they got lock A. They will wait for lock A
until it is released by t1. After lock A is released by t1, any one of
these threads will acquire lock A on the priority basis and finishes
their task. Other thread which is waiting for lock A, will never try
to acquire remaining locks.
By
defining such lock ordering, you can avoid the deadlock.
- Lock Timeout :
Another
deadlock preventive tip is to specify the time for a thread to acquire
the lock. If it fails to acquire the specified lock in the given time,
then it should give up trying for a lock and retry after some time. Such method
of specifying time to acquire the lock is called lock timeout.
- Lock the code where it is actually needed. For example, If you want only some part of the method to be thread safety, then lock only that part not the whole method.
void
method()
{
//Some statements
synchronized (this)
{
//Locking only some part of the method
}
//Some statements
}
No comments:
Post a Comment