Conditions to avoid deadlock :
1)Lock Ordering : Deadlock occurs when multiple threads need same locks but acquired in different order and hence get blocked. In order to avoid this ,make sure that threads acquire the needed locks in same order so that one thread is able to complete its task and releases the locks and after that other thread can resume its processing.
Below program doesnot follow lock ordering and results in deadlock condition .In program output you can check that neither Thread-A not thread-B complete their processing as statement is never printed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
public class DeadLockDemo { public static void main(String[] args) { Thread threadA = new Thread("Thread-A") { public void run() { System.out.println(Thread.currentThread().getName()+ " has started its processing"); synchronized (Integer.class) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " has acquired lock on Integer class and waiting to acquire lock on Float class to complete its processing"); synchronized (Float.class) { System.out.println(Thread.currentThread().getName() + " has acquired lock on Float class"); } } System.out.println(Thread.currentThread().getName()+ " has completed its processing"); } }; Thread threadB = new Thread("Thread-B") { public void run() { System.out.println(Thread.currentThread().getName()+ " has started its processing"); synchronized (Float.class) { System.out.println(Thread.currentThread().getName() + " has acquired lock on Float class and waiting to acquire lock on Integer class"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (Integer.class) { System.out.println(Thread.currentThread().getName() + " has acquired lock on Integer class"); } } System.out.println(Thread.currentThread().getName()+ " has completed its processing"); } }; threadA.start(); threadB.start(); } } |
OutPut:
Thread-B has started its processing
Thread-A has started its processing
Thread-B has acquired lock on Float class and waiting to acquire lock on Integer class
Thread-A has acquired lock on Integer class and waiting to acquire lock on Float class to complete its processing
Now, change the order of locks in the above program by taking lock on Integer class first and then Float class. In Program Output , you can check that now both Thread-a and Thread-B are able to complete their task.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
public class DeadLockDemo { public static void main(String[] args) { Thread threadA = new Thread("Thread-A") { public void run() { System.out.println(Thread.currentThread().getName()+ " has started its processing"); synchronized (Integer.class) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " has acquired lock on Integer class and waiting to acquire lock on Float class to complete its processing"); synchronized (Float.class) { System.out.println(Thread.currentThread().getName() + " has acquired lock on Float class"); } } System.out.println(Thread.currentThread().getName()+ " has completed its processing"); } }; Thread threadB = new Thread("Thread-B") { public void run() { System.out.println(Thread.currentThread().getName()+ " has started its processing"); synchronized (Integer.class) { System.out.println(Thread.currentThread().getName()+ " has acquired lock on Float class and waiting to acquire lock on Integer class..."); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (Float.class) { System.out.println(Thread.currentThread().getName() + " has acquired lock on Integer class"); } } System.out.println(Thread.currentThread().getName()+ " has completed its processing"); } }; threadA.start(); threadB.start(); } } |
OutPut :
Thread-A has started its processing
Thread-B has started its processing
Thread-B has acquired lock on Float class and waiting to acquire lock on Integer class…
Thread-B has acquired lock on Integer class
Thread-B has completed its processing
Thread-A has acquired lock on Integer class and waiting to acquire lock on Float class to complete its processing
Thread-A has acquired lock on Float class
Thread-A has completed its processing
2)Avoid nested synchronization blocks as it makes a thread to acquire another lock while it already holds one lock.This can result in deadlock in case if other thread wants to use the same lock which is held by this thread.
3)Lock the code where it is actually required and not the whole method ,so use synchronized blocks around the specific lines of code that you want to make thread safe in place of synchronized method.
4)Lock Timeout: another way to prevent deadlock is to specify time for a thread to acquire lock and If thread fails to acquire the lock in the specified time then it should give up trying for that lock and retry after some time.
5)Use Join() Method : Using join method threads can start and end sequentially as join method waits for a thread to complete its task on which it is called and then start the next thread processing.