๐ What is Deadlock in Java?
Deadlock is like two people playing “You go first” forever. Neither gives up. Neither moves. JVM says: “I'm outta here.” ๐ฉ
๐ Real-World Analogy
๐จ๐ผ Thread A grabs the Pen, waits for Paper
๐ฉ๐ผ Thread B grabs the Paper, waits for Pen
Result: Both stuck — staring at each other ๐
Outcome: Deadlock! ☠️
⚙️ Java Code Example – How Deadlock Happens
public class DeadlockExample {
private static final Object resourceA = new Object();
private static final Object resourceB = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (resourceA) {
System.out.println("Thread-1 locked Resource A");
try { Thread.sleep(100); } catch (Exception ignored) {}
synchronized (resourceB) {
System.out.println("Thread-1 locked Resource B");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (resourceB) {
System.out.println("Thread-2 locked Resource B");
try { Thread.sleep(100); } catch (Exception ignored) {}
synchronized (resourceA) {
System.out.println("Thread-2 locked Resource A");
}
}
});
t1.start();
t2.start();
}
}
๐จ Diagrammatic Representation
Time T0: Thread-1: LOCKS resourceA ๐ Thread-2: LOCKS resourceB ๐ Time T1: Thread-1: WAITING for resourceB (held by Thread-2) ⏳ Thread-2: WAITING for resourceA (held by Thread-1) ⏳ => Neither can proceed = DEADLOCK ☠️
๐ What is ReentrantLock?
Java’s ReentrantLock
is part of the java.util.concurrent.locks
package and gives more control than synchronized
.
✅ Benefits:
- Try lock with timeout ⏲️
- Interrupt lock waiting
- Fairness option (FIFO)
๐งช Example: Avoiding Deadlock with tryLock()
import java.util.concurrent.locks.*;
public class DeadlockFree {
private static final Lock lockA = new ReentrantLock();
private static final Lock lockB = new ReentrantLock();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
try {
if (lockA.tryLock(100, TimeUnit.MILLISECONDS)) {
try {
if (lockB.tryLock(100, TimeUnit.MILLISECONDS)) {
try {
System.out.println("Thread-1 got both locks");
} finally {
lockB.unlock();
}
}
} finally {
lockA.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
if (lockB.tryLock(100, TimeUnit.MILLISECONDS)) {
try {
if (lockA.tryLock(100, TimeUnit.MILLISECONDS)) {
try {
System.out.println("Thread-2 got both locks");
} finally {
lockA.unlock();
}
}
} finally {
lockB.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
}
}
๐ In-Depth: When and How Deadlock Can Happen
Deadlock can only occur if all 4 conditions happen together.
๐ 1. Mutual Exclusion
- What it means: Only one thread can use a resource at a time
- Code example:
synchronized(resourceA) {
// only one thread inside
}
✅ You can't avoid it — but you can manage it with order & timeouts
๐♂️ 2. Hold and Wait
- What it means: Thread holds one lock, waits for another
- Code example:
synchronized(resourceA) {
Thread.sleep(100);
synchronized(resourceB) {
// waiting for B while holding A
}
}
✅ Solution: Lock both at once or use tryLock()
✅ Try-Lock Solution
if (lockA.tryLock(100, TimeUnit.MILLISECONDS)) {
if (lockB.tryLock(100, TimeUnit.MILLISECONDS)) {
// Got both safely
}
}
๐ซ 3. No Preemption
- What it means: JVM won't take a lock back forcibly
- Problem: If thread holds a lock too long, others are stuck
✅ Solution: Always use finally
to release lock and prefer tryLock()
๐ 4. Circular Wait
- What it means: Threads form a circle of dependency
// Thread 1
synchronized(A) {
synchronized(B) {
// ...
}
}
// Thread 2
synchronized(B) {
synchronized(A) {
// ...
}
}
✅ Solution: Lock Ordering
Object[] locks = {resourceA, resourceB};
Arrays.sort(locks, Comparator.comparing(Object::hashCode));
synchronized(locks[0]) {
synchronized(locks[1]) {
// safe section
}
}
✅ All 4 conditions met = Guaranteed Deadlock ☠️
✅ Prevention Strategies Recap
✅ Strategy | ๐ก Benefit |
---|---|
๐ Lock in Same Order | Avoids circular wait |
⏲️ Use tryLock() | Prevents infinite waiting |
๐งผ Avoid Nested Locks | Keeps logic simple |
๐งช Use Thread Dumps | Detect stuck threads (jstack, VisualVM, JFR) |
☁️ Split Big Locks | Reduces contention |
๐ Java Joke Break
๐ง๐ป Developer: "Why does my program hang at night?"
๐ป Deadlock: "Because I’m locking your dreams too."
๐ฏ Final Tip
Deadlock doesn't throw an exception. It silently kills performance. Watch for signs like:
- High CPU usage ๐ฅ
- No logs output ๐ณ️
- Thread dumps showing "waiting to lock" ๐
Comments
Post a Comment