Tuesday, December 13, 2011

Deadlock in Java

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

Questions starts with "What is deadlock ?"
Answer is simple: When two or more threads 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.

Another way is to use "jconsole", "jconsole" will show you exactly what are the threads get 
locked and on which object.

Once you answer this, they may ask you to write code which will result in deadlock ?
Here is one of my version
===========================================================
//ThreadB.java
public class ThreadB extends Thread {
    public void run(){
        method1();
    }
    public void method1(){
        synchronized(Integer.class){
            System.out.println("ThreadB: Aquired lock on Integer.class object");
            //Nested synchronized block
            synchronized (String.class) {
                System.out.println("ThreadB: Aquired lock on String.class object");
            }
        }
    }
}
//ThreadC.java
public class ThreadC extends Thread {
    public void run(){
        method2();
    }
    public void method2(){
        synchronized(String.class){
            System.out.println("ThreadC: Aquired lock on String.class object");
            //Nested synchronized block
            synchronized (Integer.class) {
                System.out.println("ThreadC: Aquired lock on Integer.class object");
            }
        }
    }
}
//MainExample.java
public class MainExample {
    public static void main(String[] args){
        new ThreadB().start();
        new ThreadC().start();
    }
}
//Output with System/Java console Hanged:
ThreadB: Aquired lock on Integer.class object
ThreadC: Aquired lock on String.class object
===========================================================
If method1() and method2() both will be called by two or more threads, there is a good chance of 
deadlock because if Thread1 aquires lock on Sting object while executing method1() and Thread2 
acquires lock on Integer object while executing method2() both will be waiting for each other to 
release lock on Integer and String respectively to proceed further which will never happen.

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

If you have looked above code carefully you may have figured out that real reason for deadlock is 
not multiple threads but the way they access lock, if you provide an ordered access then problem 
will be resolved, here is the fixed version.

===========================================================
public void method1(){
    synchronized(Integer.class){
        System.out.println("Aquired lock on Integer.class object");
        //Nested synchronized block
        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");
        //Nested synchronized block
        synchronized (String.class) {
            System.out.println("Aquired lock on String.class object");
        }
    }
}
===========================================================
Now deadlock is fixed!!!!! There would not be any deadlock because both method is accessing 
lock on Integer and String object 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.

Hope this would be useful. Contents are copied from Internet but Example is modified and tested. Link can be seen here: 
http://javarevisited.blogspot.com/2010/10/what-is-deadlock-in-java-how-to-fix-it.html

No comments:

Post a Comment