How to avoid deadlock in Java Threads?
How to avoid deadlock in Java? is one of the popular Java interview question and flavor of the season for multi-threading, asked mostly at a senior level with lots of follow up questions. Even though question looks very basic but most of the Java developers get stuck once you start going deep.
Interview questions start with “What is a deadlock?”
The answer is simple when two or more threads are waiting for each other to release the resource they need (lock) and get stuck for infinite time, the situation is called deadlock. It will only happen in case of multitasking or multi-threading.
How do you detect deadlock in Java?
Though this could have many answers, my version is first I would look at the code if I see a nested synchronized block or calling one synchronized method from other, or trying to get a lock on a different object then there is a good chance of deadlock if a developer is not very careful.
Another way is to find it when you actually get dead-locked while running the application, try to take a thread dump, in Linux you can do this by command “kill -3”, this will print status of all threads in application log file and you can see which thread is locked on which object.
You can analyze that thread dump with using tools like fastthread.io which allows you to upload your thread dump and analyze it.
Another way is to use the jConsole/VisualVM, it will show you exactly which threads are getting locked and on which object.
Write a Java program which will result in deadlock?
Once you answer the earlier question, they may ask you to write code which will result in a deadlock in Java?
Here is one of my version:
/** * Java program to create a deadlock by imposing circular wait. * * @author WINDOWS 8 * */ public class DeadLockDemo { /* * This method request two locks, first String and then Integer */ public void method1() { synchronized (String.class) { System.out.println("Aquired lock on String.class object"); synchronized (Integer.class) { System.out.println("Aquired lock on Integer.class object"); } } } /* * This method also requests same two lock but in exactly * Opposite order i.e. first Integer and then String. * This creates potential deadlock, if one thread holds String lock * and other holds Integer lock and they wait for each other, forever. */ public void method2() { synchronized (Integer.class) { System.out.println("Aquired lock on Integer.class object"); synchronized (String.class) { System.out.println("Aquired lock on String.class object"); } } } }
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 demonstrates our program, where one thread holds a lock on one object and waiting for other object locks which are held by other thread.
You can see that Thread 1 wants the lock on object 2 which is held by Thread 2, and Thread 2 wants a lock on Object 1 which is held by Thread 1. Since no thread is willing to give up, there is a deadlock and the Java program is stuck.
How to avoid deadlock in Java?
Now the interviewer comes to the final part, one of the most important in my view;
How do you fix a deadlock in code? 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 a lock, if you provide an ordered access then the problem will be resolved.
Here is my fixed version, which avoids deadlock by a voiding circular wait with no preemption, one of the four conditions which need for deadlock.
public class DeadLockFixed { /** * 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. */ public void method1() { synchronized (Integer.class) { System.out.println("Aquired lock on Integer.class object"); synchronized (String.class) { System.out.println("Aquired lock on String.class object"); } } } public void method2() { 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 the same order. So, if thread A acquires a 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.
Thanks for reading this article so for. If you like this article then please share with your friends and colleagues. If you have any questions or feedback then please drop a note.
Published on Java Code Geeks with permission by Javin Paul, partner at our JCG program. See the original article here: How to avoid deadlock in Java Threads? Opinions expressed by Java Code Geeks contributors are their own. |