Java Deadlock: Coffman Conditions & Inter-Thread Communication (wait/notify)

When multiple threads compete for exclusive resources, two concurrency hazards arise: Deadlocks (where threads freeze waiting for each other's locks) and the need for Inter-Thread Communication (coordinating work via producer-consumer signaling).

Understanding Deadlock (The Classic Dining Philosophers Trap)

Suppose Thread 1 locks Resource A and waits for Resource B. Meanwhile, Thread 2 locks Resource B and waits for Resource A. Both threads remain frozen forever:

// DEADLOCK HAZARD DEMONSTRATION:
Object lockA = new Object();
Object lockB = new Object();

// Thread 1: Locks A, then attempts B
Thread t1 = new Thread(() -> {
    synchronized (lockA) {
        try { Thread.sleep(50); } catch (Exception e) {}
        synchronized (lockB) { System.out.println("T1 acquired both!"); }
    }
});

// Thread 2: Locks B, then attempts A (Deadlock Trap!)
Thread t2 = new Thread(() -> {
    synchronized (lockB) {
        try { Thread.sleep(50); } catch (Exception e) {}
        synchronized (lockA) { System.out.println("T2 acquired both!"); }
    }
});

Inter-Thread Communication: wait(), notify() & notifyAll()

Methods defined on java.lang.Object allowing threads to synchronize work in producer-consumer pipelines:

class MessageBuffer {
    private String message;
    private boolean hasMessage = false;

    // Consumer method
    public synchronized String take() throws InterruptedException {
        while (!hasMessage) {
            wait(); // Releases lock and sleeps until producer notifies!
        }
        hasMessage = false;
        notifyAll(); // Wakes up producer
        return message;
    }

    // Producer method
    public synchronized void put(String msg) throws InterruptedException {
        while (hasMessage) {
            wait(); // Waits for consumer to take previous message
        }
        this.message = msg;
        this.hasMessage = true;
        notifyAll(); // Signals consumer that data is ready!
    }
}

Next Step

Manually creating threads in enterprise servers is expensive. Let us explore Thread Pools with ExecutorService. Proceed to: Java ExecutorService & Pools →

Frequently Asked Questions (FAQ)

Q1. What is a Deadlock in Java multithreading?
A Deadlock is a runtime state where two or more threads are permanently blocked, each holding a lock that the other thread requires to proceed. Neither thread can continue, freezing the application.
Q2. How can Deadlocks be prevented in Java?
The most effective deadlock prevention technique is 'Lock Ordering': ensure that all threads across the entire application always acquire multiple locks in the exact same predetermined global order.
Q3. Why must wait(), notify(), and notifyAll() be called inside synchronized contexts?
These methods manipulate the underlying monitor lock of an Object. Calling them outside a synchronized block throws an IllegalMonitorStateException because the calling thread does not own the object monitor.

Explore Related Java Tutorials

Accelerate your Java mastery by studying these tightly connected core tutorials:

Thread Synchronization →

Monitor locks and mutexes.

Executor Framework →

Concurrency utilities.

Java 21 Virtual Threads →

Virtual thread concurrency.

Share Share on Facebook Share on Twitter Share on LinkedIn Pin on Pinterest Share on Stumbleupon Share on Tumblr Share on Reddit Share on Diggit

You may also like this!