简体   繁体   中英

Why this code never deadlocks when I run it?

I'm trying out deadlock concepts in Java Multithreading. I came across a code snippet which could possibly result in deadlock:

public class Deadlock {
double amount = 10.0;

public double deposit(double d) {
    amount += d;
    return amount;
}

public double withdraw(double d) {
    amount -= d;
    return amount;
}

public static void transfer(Deadlock from, Deadlock to,double d) {
    synchronized(from) {
        synchronized(to) {
            from.withdraw(d);
            try {
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(5000);
            }catch(Exception e){}

            to.deposit(d);
            System.out.println("Done");
        }
    }
}

public static void main(String[] args) {
    final Deadlock a = new Deadlock();
    final Deadlock b = new Deadlock();

    Thread t1 = new Thread(new Runnable() {
        public void run() {
            transfer(a, b, 10.0);
        }
    });
    t1.start();



    Thread t2 = new Thread(new Runnable() {
        public void run() {
            transfer(b, a, 10.0);
        }
    });
    t2.start();
}
}

Basically, the code tries to acquire locks on objects a and b at the same time. However, when I run it, the code always completes successfully. Why doesn't this deadlock?

It's simply up to the Thread scheduler if one thread is able to reach both of these

synchronized(from) {
    synchronized(to) {

before the other thread reaches the first. Add a big enough sleep between those

synchronized (from) {
    try {
        Thread.sleep(20L);
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }
    synchronized (to) {

and you should experience deadlock.

In order for the deadlock to occur, you need to have something like the following scenario happen:

t1 acquires lock a
t2 acquires lock b

t1 attempts to acquire lock b
t2 attempts to acquire lock a

Can you force this? You can try by moving your sleep statement in between lock acquisitions, but this all has to happen within a window thats not really under your direct control.

Try this:

public static void transfer(DeadLock from, DeadLock to,double d) {
    synchronized(from) {
        try {
            System.out.println(Thread.currentThread().getName() +" acquires lock " +from);
            Thread.sleep(5000);
            synchronized(to) {
                System.out.println(Thread.currentThread().getName() +" acquires lock " +to);
                from.withdraw(d);
                to.deposit(d);
                System.out.println("Done");
            }
        }catch(Exception e){}
    }
}

And to confirm you're in a deadlock, send the SIGQUIT signal to your Java process - the JVM will report the threads in a deadlock

First thread that reaches the method transfer will acquire the both the resources(to and from) so fast that that it might not be interleaved with the second thread. Having said that, this code is still prone to deadlock. The below code tries to acquire only first lock long enough to second thread getting scheduled to run:

public static void transfer(Deadlock from, Deadlock to, double d) throws InterruptedException {
    synchronized (from) {
        Thread.sleep(5000);
        synchronized (to) {
            from.withdraw(d);
            System.out.println(Thread.currentThread().getName());
            to.deposit(d);
            System.out.println("Done");
        }
    }
}

sleeping a Thread does not release the locks it holds, while waiting releases the lock

T1 has the locks over both deadlock objects, even during sleeping and only when T1 exists the respective synchronized locks , t2 gets access to it.

So to bring in deadlock, you need to sleep between the sychronized statements.

Also alternatively you can try instead of Thread.sleep(5000); to.wait(5000);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM