3

我正在查看 oracle 文档中的死锁.. 我找到了这段代码

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();
    }
}

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

我运行这段代码,它工作正常。那么一定有什么特殊的事件,什么时候会发生死锁呢?

假设先在对象上调用 bow ,当在 bower 对象上调用时,它是否会离开对对象alphonse的锁定?因为如果它保留它的锁,另一个对象上的函数在离开它的锁之前不会获得锁,它永远不会出现死锁情况。alphonsebower.bowBack(this)bowalphonse

4

5 回答 5

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();
        }
    }
于 2013-06-21T12:29:18.307 回答
4

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

假设发生这种情况:

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

  2. Thread2:gaston 进入 bow() 方法。并将锁定加斯顿物体

  3. 线程 1:alphonse 在 bow() 方法中调用 gaston 对象上的 bowBack()。

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

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

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

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

于 2013-06-21T12:36:30.930 回答
3

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

于 2013-06-21T12:30:10.717 回答
1

如果两者同时进入bow()方法,或者在

System.out.println();

如果你没有看到这两个“已经向我鞠躬了!” 消息,然后发生死锁!

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

用 Thread.sleep(1000) 扩展代码;

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

然后两个线程都进入 bow() 并且会发生解除锁定。

于 2013-06-21T12:41:09.107 回答
0

在弓A和G结束时调用bowBack,导致A调用G.bow和G调用A.bow,同时A和G的弓是同步的。所以他们都在等待对方完成。

于 2013-06-21T12:33:39.383 回答