This guide will help you understand the deadlock concept in Java. We will also take a look at ways to detect and avoid deadlock in Java using a few examples.
What you will learn:
– What is a deadlock in Java?
– Deadlock example
– How to detect a deadlock using an example.
– Best practice to avoid the deadlock in java.
A few more Multithreading Articles on Codedelay
– Thread Basics
– Race condition and Critical Section
– What is a deadlock in Java?
– What is ThreadLocal
– ExecutorService with a few examples
What is Deadlock in Java
In the last tutorial, we have discussed race conditions and how to avoid race conditions using synchronization.
As we discussed we can use the synchronized method and block to lock a portion of the code.
In java, each object has a lock, and synchronization is a way to lock a method or code block so that at a time only one thread can access that method/block.
When a thread wants to execute a synchronized method it first tries to acquire the lock.
If another thread has already acquired the lock then this thread has to wait until another thread releases the lock.
Synchronization is good to prevent data inconsistency issues.
However, there is a problem with synchronization.
Suppose there are two threads ‘Thread-A’ and ‘Thread-B’.
Let’s assume that Thread-A has acquired the lock of Object-A and Thread-B has acquired the lock of Object-B.
Now assume that Thread-A which is executing Method-A wants to acquire the lock on Object-B however Thread-B already acquires the lock on Object-B.
Furthermore, Thread-B also wants to acquire the lock on Object-A, however, Thread-A has a lock on Object-A.
In this situation both threads Thread-A and Thread-B can’t finish their execution and will wait forever for the lock.
This condition is called as the Deadlock.

Let’s understand deadlock using a Java Example
Deadlock example in Java
package com.codedelay.concurrency; import java.util.concurrent.TimeUnit; public class DeadLockDemo { private final Object object1 = new Object(); private final Object object2 = new Object(); public static void main(String[] args) { final DeadLockDemo deadLockDemo = new DeadLockDemo(); Thread t1 = new Thread(() -> { while (true) { synchronized (deadLockDemo.object1) { try { System.out.println("Inside first synchronized block of first thread t1"); TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (deadLockDemo.object2) { System.out.println("Inside second synchronized block of first thread t1"); } } } }); Thread t2 = new Thread(() -> { while (true) { synchronized (deadLockDemo.object2) { System.out.println("Inside first synchronized block of second thread t2"); synchronized (deadLockDemo.object1) { System.out.println("Inside second synchronized block of second thread t2"); } } } }); t1.start(); t2.start(); } }
In this example, we have created two threads t1 and t2.
t1 has acquired the lock of object1 and t2 has acquired the lock of the object2.
Now to process further t1 has to acquire the lock of object2.
Until t1 successfully gets object2 lock it will wait.
At the same time to process further t2 has to acquire the lock of object1.
And Until t2 successfully gets object1 lock it will wait.
This scenario is called a deadlock.
How to detect and avoid deadlock
Although it is not easy to detect and avoid deadlock compile time.
There are few ways to detect deadlock at runtime.
Let’s discuss a few ways to detect the deadlock.
Deadlock detection using ThreadMXBean
Once you already entered into deadlock condition then you can get further information about threads that are blocked due to deadlock.

ThreadMxBean
is an interface in java.lang.management
.
ThreadMxBean is a management interface of JVM’s thread system.
ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long ids[] = bean.findMonitorDeadlockedThreads(); ThreadInfo threadInfo[] = bean.getThreadInfo(ids); System.out.println(threadInfo.length); for (ThreadInfo info : threadInfo) { //returns the name of deadlocked thread System.out.println(info.getThreadName()); }
As you could see in the above example we are calling findMonitorDeadlockedThreads
from the ThreadMXBean
instance.
findMonitorDeadlockedThreads returns threads information that are currently in deadlock (waiting to acquire locks).

Let me show you a complete example and output.
package com.codedelay.concurrency; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.util.concurrent.TimeUnit; public class DeadLockDemo { private final Object object1 = new Object(); private final Object object2 = new Object(); public static void main(String[] args) { final DeadLockDemo deadLockDemo = new DeadLockDemo(); Thread t1 = new Thread(() -> { while (true) { synchronized (deadLockDemo.object1) { try { System.out.println("Inside first synchronized block of first thread t1"); TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (deadLockDemo.object2) { System.out.println("Inside second synchronized block of first thread t1"); } } } }); Thread t2 = new Thread(() -> { while (true) { synchronized (deadLockDemo.object2) { System.out.println("Inside first synchronized block of second thread t2"); synchronized (deadLockDemo.object1) { System.out.println("Inside second synchronized block of second thread t2"); } } } }); Thread t3 = new Thread(() -> { System.out.println("Hello World"); try { TimeUnit.SECONDS.sleep(6); } catch (InterruptedException e) { e.printStackTrace(); } }); t1.start(); t2.start(); t3.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getThreadDump()); } public static String getThreadDump() { final StringBuilder threadInfoStr = new StringBuilder(); ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); // long ids[] = threadMXBean.findMonitorDeadlockedThreads(); // ThreadInfo threadInfo[] = threadMXBean.getThreadInfo(ids); final ThreadInfo[] threadInfo = threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds(), 100); System.out.println(threadInfo.length); for (ThreadInfo info : threadInfo) { threadInfoStr.append('"'); threadInfoStr.append(info.getThreadName()); threadInfoStr.append("\" "); final Thread.State state = info.getThreadState(); threadInfoStr.append("\n java.lang.Thread.State: "); threadInfoStr.append(state); final StackTraceElement[] stackTraceElements = info.getStackTrace(); for (final StackTraceElement stackTraceElement : stackTraceElements) { threadInfoStr.append("\n at "); threadInfoStr.append(stackTraceElement); } threadInfoStr.append("\n\n"); } return threadInfoStr.toString(); } }
Output of the above program would be
"main" java.lang.Thread.State: RUNNABLE at java.management@12/sun.management.ThreadImpl.getThreadInfo1(Native Method) at java.management@12/sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:190) at app//com.codedelay.concurrency.DeadLockDemo.getThreadDump(DeadLockDemo.java:70) at app//com.codedelay.concurrency.DeadLockDemo.main(DeadLockDemo.java:60) "Reference Handler" java.lang.Thread.State: RUNNABLE at java.base@12/java.lang.ref.Reference.waitForReferencePendingList(Native Method) at java.base@12/java.lang.ref.Reference.processPendingReferences(Reference.java:241) at java.base@12/java.lang.ref.Reference$ReferenceHandler.run(Reference.java:213) "Finalizer" java.lang.Thread.State: WAITING at java.base@12/java.lang.Object.wait(Native Method) at java.base@12/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:155) at java.base@12/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:176) at java.base@12/java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:170) "Signal Dispatcher" java.lang.Thread.State: RUNNABLE "Attach Listener" java.lang.Thread.State: RUNNABLE "Common-Cleaner" java.lang.Thread.State: TIMED_WAITING at java.base@12/java.lang.Object.wait(Native Method) at java.base@12/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:155) at java.base@12/jdk.internal.ref.CleanerImpl.run(CleanerImpl.java:148) at java.base@12/java.lang.Thread.run(Thread.java:835) at java.base@12/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:134) "Thread-0" java.lang.Thread.State: BLOCKED at app//com.codedelay.concurrency.DeadLockDemo.lambda$0(DeadLockDemo.java:25) at app//com.codedelay.concurrency.DeadLockDemo$$Lambda$1/0x0000000801200840.run(Unknown Source) at java.base@12/java.lang.Thread.run(Thread.java:835) "Thread-1" java.lang.Thread.State: BLOCKED at app//com.codedelay.concurrency.DeadLockDemo.lambda$1(DeadLockDemo.java:36) at app//com.codedelay.concurrency.DeadLockDemo$$Lambda$2/0x0000000801200c40.run(Unknown Source) at java.base@12/java.lang.Thread.run(Thread.java:835) "Thread-2" java.lang.Thread.State: TIMED_WAITING at java.base@12/java.lang.Thread.sleep(Native Method) at java.base@12/java.lang.Thread.sleep(Thread.java:340) at java.base@12/java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446) at app//com.codedelay.concurrency.DeadLockDemo.lambda$2(DeadLockDemo.java:45) at app//com.codedelay.concurrency.DeadLockDemo$$Lambda$3/0x0000000801201040.run(Unknown Source) at java.base@12/java.lang.Thread.run(Thread.java:835)
How to avoid Deadlock
Deadlocks are bad.
Your complete application stops working once it faces a deadlock condition.
Moreover, when you get deadlock condition in a production application, then it is not just hard to troubleshoot but also very difficult to fix them.
However, you can avoid deadlocks by taking care of a few steps.
- Try to avoid nested synchronization blocks.
In nested synchronization block one thread try to acquire another lock when it is already holding one lock. - Lock ordering: If you can’t avoid nested synchronization block then you should make sure that threads will acquire locks in the same order. In the above example, one thread firstly acquired the lock on object1 and then tried to acquire an object2 lock.
However, thread t2 acquired object2 lock first then tried to acquire the lock of object1.
Hence deadlock occurred. - Lock Timeout: You can also specify a timeout.
If a thread fails to acquire a lock then it should wait for a specific time before retry to acquire the lock.
Conclusion
In this tutorial, we discussed Deadlock in Java, how to detect deadlock and how to avoid them with a few examples.