0
public class DeadlockDemo2 {

    public static Object Lock1 = new Object();
    public static Object Lock2 = new Object();

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ThreadDemo1 demo1 = new ThreadDemo1();
        ThreadDemo2 demo2 = new ThreadDemo2();
        demo1.start();
        demo2.start();
    }

    private static class ThreadDemo1 extends Thread {
        public void run() {
            synchronized (Lock1) {
                System.out.println("Thread 1: Holding lock 1...");

                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                }
                System.out.println("Thread 1: Waiting for lock 2...");

                synchronized (Lock2) {
                    System.out.println("Thread 1: Holding lock 1 & 2...");
                }
            }
        }
    }

    private static class ThreadDemo2 extends Thread {
        public void run() {
            synchronized (Lock2) {
                System.out.println("Thread 2: Holding lock 2...");

                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                }
                System.out.println("Thread 2: Waiting for lock 1...");

                synchronized (Lock1) {
                    System.out.println("Thread 2: Holding lock 1 & 2...");
                }
            }
        }
    }
}

In above program, both Threads are sleeping for 10 milliseconds. So once the time expires, demo1 can acquire lock on lock2 and demo2 on lock1. But It does not happen so. They go under deadlock.

Can somebody explain the reason?

Thanks in advance.

1 Answers1

0

We'll ignore the design issues here and assume you're just trying to understand threading with a toy example.

The problem is your lock scoping. Let's list out the order of operations here:

In ThreadDemo1:

  1. Acquire Lock1
  2. Sleep
  3. Acquire Lock2
  4. Free Lock2
  5. Free Lock1

Similarly, in ThreadDemo2:

  1. Acquire Lock2
  2. Sleep
  3. Acquire Lock1
  4. Free Lock1
  5. Free Lock2

As you can see from the order of operations here, both of your ThreadDemo classes attempt to acquire the other lock before freeing their initial lock. This basically guarantees deadlock as they will be stuck forever waiting for the other to release their initial lock.

What you actually wanted to happen was this in ThreadDemo1:

  1. Acquire Lock1
  2. Sleep
  3. Free Lock1
  4. Acquire Lock2
  5. Free Lock2

And this in ThreadDemo2:

  1. Acquire Lock2
  2. Sleep
  3. Free Lock2
  4. Acquire Lock1
  5. Free Lock1

To do this, simply change this:

private static class ThreadDemo1 extends Thread {
    public void run() {
        synchronized (Lock1) {
            System.out.println("Thread 1: Holding lock 1...");

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
            }
            System.out.println("Thread 1: Waiting for lock 2...");

            synchronized (Lock2) {
                System.out.println("Thread 1: Holding lock 1 & 2...");
            }
        } // <----- We're going to move this bracket
    }
}

To this:

private static class ThreadDemo1 extends Thread {
    public void run() {
        synchronized (Lock1) {
            System.out.println("Thread 1: Holding lock 1...");

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
            }
        } // <----- We moved it here
        System.out.println("Thread 1: Waiting for lock 2...");

        synchronized (Lock2) {
            System.out.println("Thread 1: Holding lock 1 & 2...");
        }
    }
}

And make the same change in your ThreadDemo2 class

aruisdante
  • 8,875
  • 2
  • 30
  • 37
  • Thanks for the explanation. It is really helpful. I just have one doubt, if there is no sleep() call it works fine. Even in that case will it not be deadlocked? – Yogesh Malhotra Jan 05 '17 at 17:27
  • Without the sleep, it's theoretically possible for `ThreadDemo1` to finish all of its work before `ThreadDemo2` even starts executing thanks to thread-spinup time and scheduling timing. So it's not that you've removed the deadlock, it's just that you happen to be missing it. If you instead replaced the sleep with some longer unit of work, then you'd like hit the deadlock again. – aruisdante Jan 05 '17 at 17:31
  • ok. Thanks. I came across one more program which I cannot paste it here @ http://www.journaldev.com/1058/deadlock-in-java-example . If the program is run as it is, it does not end. If I change the sleep duration to say 1000ms from 30000(which is given) in the work() method, all thread runs one by one. I don't understand how does sleep affect the output here? Can you throw some light on it? – Yogesh Malhotra Jan 05 '17 at 18:13
  • Can you plz explain? – Yogesh Malhotra Jan 06 '17 at 15:01