What is a deadlock in Java and how can you avoid it?

A deadlock is a concurrency issue where two or more threads become permanently blocked because each thread is waiting for a resource that is currently locked by another thread. As a result, none of the threads can continue execution, causing the application to hang.

Key Points: • Deadlocks usually occur when multiple threads acquire locks in different orders. • Threads involved in a deadlock remain waiting indefinitely unless external intervention occurs. • Proper lock management and modern concurrency utilities help prevent deadlock situations.

Example: Imagine two employees sharing two printers. Employee A holds Printer 1 and waits for Printer 2, while Employee B holds Printer 2 and waits for Printer 1. Since both are waiting for each other, neither can continue. This is similar to a deadlock in Java.

Code Example:

public class DeadlockExample {

    private static final Object LOCK1 = new Object();
    private static final Object LOCK2 = new Object();

    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            synchronized (LOCK1) {
                synchronized (LOCK2) {
                    System.out.println("Thread 1 completed");
                }
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (LOCK2) {
                synchronized (LOCK1) {
                    System.out.println("Thread 2 completed");
                }
            }
        });

        t1.start();
        t2.start();
    }
}

Interview Tip: A concise interview answer is: A deadlock occurs when two or more threads wait indefinitely for resources locked by each other. It can be avoided by acquiring locks in a consistent order, reducing nested locking, using lock timeouts, and leveraging concurrency utilities from java.util.concurrent.