Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
Hello Ninjas! Learning Java? Got stuck in handling deadlocks? Don’t worry, we got you covered, as this article will make you learn everything about deadlocks in Java and also will discuss some of the tips to avoid deadlocks so that you can code freely.
Before starting learning about the deadlock in Java, learn about Multithreading in Java.
In brief, Multithreading is the process of Java that makes two or more parts of the program execute parallely to make the utmost use of the CPU. Now let us learn about the deadlock in the next section.
What is a Deadlock in Java?
Deadlock in Java is a condition where two or more threads are blocked forever, each waiting for the other to release a lock. Deadlock occurs in multithreaded applications when threads try to acquire locks on resources in a circular manner, leading to a situation where none of the threads can proceed.
Deadlock in Java occurs when two or more threads are blocked forever, each waiting for the other to release a resource. This usually happens due to resource contention and improper synchronization in multithreaded programs. When multiple threads try to acquire locks on shared resources in an uncoordinated way, they can end up waiting indefinitely, causing the program to freeze.
Deadlock typically arises when the following four necessary conditions occur simultaneously:
Mutual Exclusion: At least one resource must be held in a non-shareable mode.
Hold and Wait: A thread holding a resource is waiting to acquire additional resources held by other threads.
No Preemption: Resources cannot be forcibly taken from threads; they must be released voluntarily.
Circular Wait: A set of threads are waiting on each other in a circular chain.
Example of deadlock in Java
Let us see a java code that portrays an example of the Deadlock condition in Java.
Code
Java
Java
// A java program to portray deadlock public class DeadlockExample { public static void main(String[] args) { final String r1 = "Ankit kumar"; final String r2 = "Aman shivhare"; // Here Thread1 tries to lock r1 and then r2 Thread Thread1 = new Thread() { public void run() { synchronized (r1) { System.out.println("Thread 1: locked r 1"); try { Thread.sleep(100);} catch (Exception e) {}
The system enters into a deadlock situation in the above-quoted example.
Any system can also see some complex deadlock which not only involves two but more threads that are waiting for object locks that are acquired by other threads. They become more complicated, and eventually, they are hard to resolve. Let us see one such case.
Complex deadlocks
If any code in such a manner such that the following conditions mark true for them, then they are believed to be a complex deadlock!
Thread 1 locks X waits for Y
Thread 2 locks Y waits for Z
Thread 3 locks Z waits for W
Thread 4 locks W, waits for X
Here Thread 1 waits for thread 2, thread two waits for thread 3, thread three waits for thread 4, and thread four waits for thread 1.
So this was a case for a complex deadlock. Now the question arises here is how can we handle them? Let us answer this in the following section.
Handling Deadlocks
If we can somehow change the pattern or the order of the statements that are used to access the shared resources, then we can handle the simpler deadlocks easily. Let us see the code for it.
Code
Java
Java
// A java program to solve deadlock public class Deadlock_Solved { public static void main(String ar[]) { Deadlock_Solved example = new Deadlock_Solved(); final r1 x = example.new r1(); final r2 y = example.new r2(); // Thread-1 Runnable y1 = new Runnable() { public void run() { synchronized (y) { try { // Adding delay so that both threads can start trying to lock resources Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // Thread-1 do have resource1 but also need resource2 synchronized (x) { System.out.println("In block 1"); } } } }; // Thread-2 Runnable y2 = new Runnable() { public void run() { synchronized (y) { // Thread-2 have resource2 but need resource1 also synchronized (x) { System.out.println("In block 2"); } } } }; new Thread(y1).start(); new Thread(y2).start(); } // resource1 private class r1 { private int p = 10; public int getI() { return p; } public void setI(int p) { this.p = p; } // resource2 } private class r2 { private int p = 20;
public int getI() { return p; } public void setI(int p) { this.p = p; } } }
You can also try this code with Online Java Compiler
So this was how we handled the simple deadlock condition for two threads. But Solving the complex deadlock situation can be very challenging, so we need to avoid certain things which are discussed in the next section.
We simply cannot vanish the chances of the system attaining a deadlock situation, but if we follow certain ways, then we can avoid them to a greater extent.
Avoid nested locks: Nested locks refer to a situation where a thread holds a lock on one resource and attempts to acquire a lock on another resource. When multiple threads are involved, this can quickly lead to a circular dependency, causing deadlock.
Avoid unnecessary locks: Using more locks than required can complicate code and increase the chance of deadlock. Unnecessary locks can also reduce program efficiency, as threads may spend more time waiting on locks that aren’t essential.
Using thread join: The Thread.join() method allows one thread to wait for the completion of another. This approach can help avoid deadlock by ensuring that threads complete their work in a specific order, reducing the chance of circular waiting.
With learning these techniques to avoid the possibility of a deadlock, we come to the end of this blog. Let us try to answer some of the FAQs related to this topic.
Deadlock occurs when two or more threads are permanently blocked, each waiting for resources held by the other. In this situation, none of the threads can proceed, and the program comes to a standstill. Deadlock usually happens due to improper lock ordering or poor resource management in multithreaded environments. For example, if Thread A holds Lock 1 and waits for Lock 2, while Thread B holds Lock 2 and waits for Lock 1, both threads will wait forever. Key Point: Threads are completely blocked and cannot continue.
Livelock
Livelock is a situation where threads remain active and constantly changing their states, but they are unable to make progress because they keep reacting to each other’s actions. Unlike deadlock, the threads are not stuck waiting; instead, they keep retrying operations without success. For example, imagine two people continuously stepping aside to let each other pass in a narrow hallway, but neither gets through. Key Point: Threads are not blocked but are stuck in an endless cycle without completing their tasks.
Starvation
Starvation occurs when a thread waits indefinitely for a resource because other threads are constantly given preference. This usually happens when lower-priority threads are repeatedly bypassed by higher-priority ones, or when resources are heavily contested. For example, in a busy restaurant, a customer who always gets skipped by waiters serving other tables may never get served. Key Point: A thread is ready to execute but is continuously ignored due to scheduling or priority rules.
Key Differences
Feature
Deadlock
Livelock
Starvation
Thread State
Permanently blocked
Actively running but stuck
Waiting indefinitely
Cause
Circular resource waiting
Constant response to others
Resource preference or priority
Progress
No
No
Other threads make progress
Example
Two threads holding locks
Two people stepping aside repeatedly
Low-priority thread never gets CPU time
Deadlock: Threads block each other.
Livelock: Threads keep working but achieve nothing.
Starvation: Threads are overlooked and never get resources.
Frequently Asked Questions
What is deadlock and its 4 types?
Deadlock is a situation where threads are indefinitely blocked, waiting for each other's resources. The types are mutual exclusion, hold and wait, no preemption, and circular wait.
What is an example of a deadlock?
A common deadlock example involves two threads, where each thread holds one lock and waits for a second lock held by the other.
How to handle deadlock exceptions in Java?
Java doesn't throw specific deadlock exceptions. To handle deadlocks, use lock ordering, tryLock() with timeouts, or detect circular dependencies in threads.
How can we avoid Deadlocks?
We can avoid deadlocks by avoiding the use of nested or some unnecessary locks and by using thread join.
Can we resolve a deadlock in Java?
Yes, we can resolve a deadlock condition in Java by simply reordering the statements that are used to access the shared resources.
Conclusion
In this article, we have extensively discussed deadlock in Java along with its example. We also saw many ways which can minimise the chance of any system getting into a deadlock situation. We saw two codes, one with the deadlock and the another after reordering the statements which were used to access the shared resources. In the end, we answered some of the frequently asked questions related to this topic.
Live masterclass
Beginner to GenAI Engineer Roadmap for 30L+ CTC at Amazon
by Shantanu Shubham
23 Feb, 2026
03:00 PM
Zero to Data Analyst: Amazon Analyst Roadmap for 30L+ CTC
by Abhishek Soni
22 Feb, 2026
06:30 AM
Top GenAI Skills to crack 30 LPA+ roles at Amazon & Google
by Sumit Shukla
22 Feb, 2026
08:30 AM
Data Analysis for 20L+ CTC@Flipkart: End-Season Sales dataset
by Sumit Shukla
23 Feb, 2026
01:30 PM
Beginner to GenAI Engineer Roadmap for 30L+ CTC at Amazon
by Shantanu Shubham
23 Feb, 2026
03:00 PM
Zero to Data Analyst: Amazon Analyst Roadmap for 30L+ CTC