【问题标题】:A question about Deadlock from the Sun tutorialsSun教程中关于死锁的问题
【发布时间】:2010-02-16 05:48:25
【问题描述】:

下面是直接来自描述死锁的 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 时极有可能会阻塞。这两个块都不会结束,因为每个线程都在等待另一个退出弓。

【问题讨论】:

标签: java


【解决方案1】:

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

alphonse.bow 抓住了 alphonse 的锁,而 gaston.bow 抓住了 gaston 的锁。当 'alphonse' 线程在 bow 中时,它会尝试在 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 创建/启动之前挂起主线程),则不会发生死锁。

【讨论】:

  • alphonse 如何试图锁定加斯顿。 alphonse 始终使用 alphonse 实例。
  • 我不明白下面的“当 'alphonse' 线程在 bow 中时,它会尝试在 bower.bowBack 上抓住 'gaston' 上的锁。” 'alphonse' 如何试图锁定 gaston 实例。
  • 第一个线程调用 alphonse.bow(gaston)。此时,线程对 alphonse 有一个锁。一旦该方法进入 bower.bowBack,bower 是 gaston,它就会尝试锁定 gaston。 “alphonse”是指运行“alphonse.bow(gaston)”的线程;抱歉,如果不清楚。
  • 啊...我现在明白了。在 bower.bowBack(this); bower = gaston - 出于某种原因,我认为 bower 是 alphonse
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-18
相关资源
最近更新 更多