Pages

How to avoid deadlock in Java? is one of the question which is flavor of the season for multi-threading, asked more at a senior level and with lots of follow up questions. Even though question looks very basic but most of developer get stuck once you start going deep.

Interview questions starts with "What is deadlock?"
Answer is simple, when two or more threads are waiting for each other to release lock and get stuck for infinite time, situation is called deadlock . It will only happen in case of multitasking.

How do you detect deadlock in Java ?

Though this could have many answers , my version is first I would look the code if I see nested synchronized block or calling one synchronized method from other or trying to get lock on different object then there is good chance of deadlock if developer is not very careful.

Other way is to find it when you actually get locked while running the application , try to take thread dump , in Linux you can do this by command "kill -3" , this will print status of all the thread in application log file and you can see which thread is locked on which object.

Other way is to use jconsole, it will show you exactly which threads are get locked and on which object.

Write a Java program which will result in deadlock?

Once you answer this , they may ask you to write code which will result in deadlock ?
here is one of my version

If method1() and method2() both will be called by two or many threads , there is a good chance of deadlock because if thread 1 acquires lock on Sting object while executing method1() and thread 2 acquires lock on Integer object while executing method2() both will be waiting for each other to release lock on Integer and String to proceed further which will never happen.

This diagram exactly demonstrate our program, where one thread holds lock on one object and waiting for other object lock which is held by other thread.

How to avoid deadlock in Java?

Now interviewer comes to final part, one of the most important in my view; How do you fix deadlock? or How to avoid deadlock in Java?

If you have looked above code carefully then you may have figured out that real reason for deadlock is not multiple threads but the way they are requesting lock , if you provide an ordered access then problem will be resolved , here is my fixed version, which avoids deadlock by avoiding circular wait with no preemption.

publicclassDeadLockFixed {
/**
* Both method are now requesting lock in same order, first Integer and then String.
* You could have also done reverse e.g. first String and then Integer,
* both will solve the problem, as long as both method are requesting lock
* in consistent order.
*/publicvoidmethod1() {
synchronized (Integer.class) {
System.out.println("Aquired lock on Integer.class object");
synchronized (String.class) {
System.out.println("Aquired lock on String.class object");
}
}
}
publicvoidmethod2() {
synchronized (Integer.class) {
System.out.println("Aquired lock on Integer.class object");
synchronized (String.class) {
System.out.println("Aquired lock on String.class object");
}
}
}
}

Now there would not be any deadlock because both methods are accessing lock on Integer and String class literal in same order. So, if thread A acquires lock on Integer object , thread B will not proceed until thread A releases Integer lock, same way thread A will not be blocked even if thread B holds String lock because now thread B will not expect thread A to release Integer lock to proceed further.

never read such a great article on deadlock. deadlock in java or any other programming language is quite common because of multi-threading behavior and I agree its favorite interview topic. the best part of this java interview is how to fix deadlock in java, simply great.

Hi Arseny Kovalchuk, Thanks for your example but will you explain what is difference between earlier example and this for everybody's understanding , what I see run() method of your example is similar to method1, Also to get guaranteed deadlock one can use Sleep to hold one thread to hold the lock and increase deadlock chance , isn't it ?

@Javin, The main difference in my sample is that the synchronized block in the run methods are nested. And the major thing to get a deadlock is

1. threadOne acquires the lock on monitorOne2. threadTwo acquires the lock on monitorTwo3. threadOne wants to get lock on monitorTwo, but !mportant! it should not release lock on monitorOne, until it gets the lock on monitorTwo4. at this time threadTwo wants to get lock on monitorOne, and it doesn't release lock on monitorTwo, until it gets lock on monitorOne.

That's the deadlock. In your sample there is a possibility for both threads to release the lock!

Hi Arseny Kovalchuk, Your Explanation is quite clear and indeed in this condition deadlock will occur, but in my program also synchronized blocks are nested because until its nested probability of deadlock reduces, is it formatting or am I missing something ?

Hi Javin,I came across a scenario of deadlock in my application and after struggling for a while to detect it, I used the java.util.concurrent.locks.Lock.tryLock(time, unit) method which waits for specified time to acquire a lock and returns a boolean. I used this method for every lock in that scenario and logged the scenario when it could not acquire the lock. This helped me identify and fix all the possible scenarios which can cause dead lock at run time.Thought, it might be useful to someone if they are trying to detect a dead lock.

Thanks for your comment Santosh, isn't tryLock() can return even if there is no deadlock I mean it just not been able to acquire the lock within specified period. I guess taking a thread dump by using kill -3 is another way of finding out which thread is waiting for which lock and than detecting deadlock pattern. JConsole also helps you to find deadlock in Java. Anyway tryLock() can also be used as Indicator and thanks for raising this point.

You are right Javin, tryLock() false just indicates failure to acquire lock in the specified time. But if we carefully choose the time, based on the context that would only be possible in case of a deadlock (e.g. 10 or 20 minutes) than it would be unlikely that its anything other than a dead lock.

Using kill -3 is a good way, but it requires a manual intervention at the particular time. By putting the tryLock(), we can check the logs anytime.

Using tryLock() can also be used to write some recovery code and the system will never crash because of a dead lock. In worst case a process has to die.

On event of deadlock in java application you can do following to investigate it:

1) By pressing Ctrl+Break on Windows machines print thread dump in console of Java application. by analyzing this thread dump you will know cause of deadlock.

2) On Linux and Solaris machine you can take thread dump by sending SIGQUIT or kill -3 to Java application process id. From Java 6 onwards budled Jconsole utility can also be attached to hung java process and find out deadlocks in it.

Hi,Its a gr8 article.. I understood how it results in deadlock but I didnt understand the explanation behind the fix.. I mean u just changed the order. Could u explain the flow please as to how deadlock will not arise ones the order s changed Threads n Java has been my weakest area hence the unclarity

Hi Pallavi,not a problem, threads in Java are always confusing. original order of acquring lock in two methods are opposite e..g in method 1 its lock 1-->lock2 while in method 2 its lock2-->lock1 which can result in deadlock because if two thread calls method 1 and method 2 thread 1 may end of lock 1 and thread 2 end of lock 2 and both will wait for other locks, i.e. deadlock.

By having a particular order of acquiring lock e.g. lock1-->lock2 in both method we can eliminate this problem. Also remember to release locks in opposite order e.g. lock2--> lock1.

You can also use TIMED and POLLED locks from ReentrantLock to have a probabilistic deadlock avoidation. By using timed and polled lock acquision approach, one thread will eventually back-off, giving another thread to either acquire or release the lock. Though this is not guaranteed, it certainly helps to reduce probability of deadlock in Java program.

Imposing ordering is an example of avoiding deadlock by braking "Circular Wait" condition. As you know, in order for a deadlock to occur, four condition must met :

1) Mutual Exclusion2) Hold and Wait3) No Preemption4) Circular Wait

Though you can break any of these conditions to avoid deadlock, it's often easy to break circular wait. But, even with consistent ordering, you can not prevent deadlock, if order is not predefined i.e. if Id of next resource comes after acquiring first resource, your system still get into deadlock. This is true for all programming language, which supports multi-threading and concurrency, not just Java.

If you talk about How to detect deadlock in Java, then there is a cleaver way by using ThreadMXBean, which provides a method called findDeadLockthreads() which returns id of all those thread which are in deadlock and waiting for each other to release monitor or acquire lock. here is the code :

Just remember, how critical is to write a deadlock free concurrent application in Java, because only way to break deadlock is to restart the server. If you could create deadlock detector at runtime, which can also break deadlock as and when they happen, may be by intruppting or killing thread, without losing data invariant than, it would be just fantastic.

I would like to point one mistake in this code, since I used the example above in one of my interviews and the interviewer took my case because he was very unhappy with the performance of the above code, even after reordering the locks.

When you sue the synchronized block and obtain the lock on something like Integer.class or String.class, you are blocking the entire class object. It is generally a very bad idea to obtain locks on class objects directly. A better way if you are not using the lock interface is using the following lines:

Object lock1 = new Object();Object lock2 = new Object();

This way you are just obtaining the intrinsic locks of these objects rather than the entire Object.class object. Even when explaining I would request you to take care of bad practices like these, since sometimes beginners can pick up bad habits and continue them until their case is taken by someone :P.

Hello Bhavya Shah, you are absolutely correct, using String.class or Integer.class or just using class literal from any other class is NOT a good idea. In fact, I have also pointed this fact on my article on Java synchronization. I completely agree with you that beginners can pick up these as it is, hopefully this will improve quality of examples going forward. On another noted, using Object lock = new Object(); is probably one of the best use of Object class as well. Once again, thanks for your comment.

'Now there would not be any deadlock because both method is accessing lock on Integer and String object in same order' What if I really need to acces the locks in the reverse order. How do I deal with that?

I know what is dead Lock and how it forms in program but in above explanation and example what you gave is i dint get you used synchronized lock which is nested instead of nested if we use non-nested loop than we can avoid deadlocks

@Anonymous, if situation demand that you need multiple locks to access a resource then you have to. For example, how do you access something which is behind two doors? Accessing them in proper order helps to break the deadlock.

http://fastthread.io/ is a universal thread dump analyser. It parses complex thread dumps and presents with you with insightful metrics and beautiful graphs. I will recommend this tool to all my java team members.