这个java代码如何产生死锁?

时间:2013-06-21 12:26:29

标签: java multithreading deadlock

我正在通过oracle docs进行僵局。 我找到了这段代码

public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s"
                + "  has bowed to me!%n", 
                this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s"
                + " has bowed back to me!%n",
                this.name, bower.getName());
        }
    }

    public static void main(String[] args) {
        final Friend alphonse =
            new Friend("Alphonse");
        final Friend gaston =
            new Friend("Gaston");
        new Thread(new Runnable() {
            public void run() { alphonse.bow(gaston); }
        }).start();
        new Thread(new Runnable() {
            public void run() { gaston.bow(alphonse); }
        }).start();
    }
}

我无法理解,在什么情况下会发生死锁?

我运行此代码,它运行正常。所以必须有一些特殊的事件,什么时候会发生死锁?

假设首先在alphonse对象上调用bow,当在bower对象上调用alphonse时它是否会锁定bower.bowBack(this)对象? 因为如果它保留了它的锁定,那么在bow保持锁定之前,另一个对象上的alphonse函数将不会被锁定,并且它永远不会成为死锁情况。

5 个答案:

答案 0 :(得分:4)

如果在打印第一行之后并且在调用bowBack之前放置了Thread.sleep(1000),则应该看到死锁。无论如何都会发生这种僵局,这种情况很少发生。

你有两个线程和两个被获取的锁是不同的命令。这可以使每个线程保持一个锁但无法获得第二个锁。即死锁。

注意:线程需要花费大量时间才能启动,这意味着第一个线程可以在第二个线程启动之前运行完成,因此您不太可能看到问题。


这是给你的益智游戏。这会造成僵局,你能明白为什么吗?

class A {
    static final int i;
    static {
        i = 128;

        Thread t = new Thread() {
            public void run() {
                System.out.println("i=" + i);
            }
        };
        t.start();
        try {
           t.join();
        } catch (InterruptedException e) {
           Thread.currentThread().interrupt();
        }
    }

答案 1 :(得分:4)

你有2个对象,alphonse和gaston以及2个线程,Thread1和Thread2

假设发生这种情况:

  1. Thread1:alphonse进入bow()方法。并将锁定alphonse对象

  2. Thread2:gaston进入bow()方法。并将锁定gaston对象

  3. Thread1:在bow()方法中使用alphonse,在gaston对象上调用bowBack()。

    - > Thread1将阻塞,因为Thread2已经锁定了gaston

  4. Thread2:gaston在bow()方法中,在alphonse对象上调用bowBack()。

    - > Thread2将阻塞,因为Thread1已经锁定了alphonse

  5. 所以现在Thread1正在等待Thread2。而Thread2正在等待Thread1。这是一个僵局。

答案 2 :(得分:3)

当您处理多线程时,两个线程中的操作可能以任何顺序相互发生。因此,假设在这种情况下两个actor都执行bow,然后他们都尝试执行bow_back。当bowbow_back同步时,两个对象都将被锁定,您将无法对其中的任何对象执行bow_back。两个对象都会等到另一个对象“空闲”,这不会发生,因为bow在它“退回”之前不会返回。

答案 3 :(得分:1)

如果两者同时或在

期间输入bow()方法,则会发生交易
System.out.println();

如果你没有看到两个“已经向我退回!”消息,那么就会发生死锁!

如果第一个线程在第二个线程开始之前终止,则不存在死锁。

使用Thread.sleep(1000);

扩展代码
public synchronized void bow(Friend bower) {
System.out.println(....);
Thread.sleep(1000);
...
}

然后两个线程都进入bow()并且会发生交易。

答案 4 :(得分:0)

在弓A和G的最后一个叫BowBack,导致从A的一个G.bow和来自G的A.bow的召唤,而A和G的弓是同步的。所以他们都等着彼此完成。