关于来自Sun教程的死锁的问题

时间:2010-02-16 05:48:25

标签: java

以下是直接来自描述死锁的Sun教程的代码。但是我不明白在这种情况下死锁是如何发生的,因为两种方法都是同步的。两个线程如何同时在同一个同步方法中?

死锁描述了两个或多个线程永远被阻塞,等待彼此的情况。这是一个例子。

Alphonse和Gaston是朋友,并且很有礼貌的信徒。严格的礼貌规则是,当你向朋友鞠躬时,你必须保持鞠躬,直到你的朋友有机会归还弓箭。不幸的是,这条规则没有考虑到两个朋友可能同时互相鞠躬的可能性。这个示例应用程序Deadlock模拟了这种可能性:

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

当Deadlock运行时,两个线程在尝试调用bowBack时极有可能会阻塞。两个块都不会结束,因为每个线程都在等待另一个线程退出弓。

1 个答案:

答案 0 :(得分:8)

同步(实例)方法锁定对象,而不是类。

alphonse.bow抓住阿尔方斯和gaston.bow的锁定抓住gaston上的锁。当'alphonse'线程处于低位时,它试图抓住bower.bowBack上'gaston'的锁。同样,'gaston'试图抓住'alphonse'的锁定。

为了清晰起见而编辑(我希望):

让我们调用两个线程Thread1和Thread2。

Thread1运行alphonse.bow(gaston),它抓住alphonse对象上的锁,而Thread2运行gaston.bow(alphonse)并抓住gaston对象上的锁。

在Thread1中,当它试图运行bower.bowBack(this)时,bower = gaston,线程需要先获取gaston上的锁。

在这种情况下,Thread2尝试用bower = alphonse做同样的事情。 Thread1有一个Thread2需要的锁,反之亦然,这就是发生死锁的原因。

顺便说一句,不必总是发生死锁。如果Thread1可以在Thread2有机会之前启动和完成(例如,如果在Thread1启动之后但在创建/启动Thread2之前某些东西挂起主线程),则不会发生死锁。