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

当我运行该程序时,我得到的输出为

阿方斯:加斯顿向我鞠躬!
加斯顿:阿方斯向我鞠躬!

那么两个线程可以同时访问同步方法吗?

最佳答案



这取决于两个线程试图锁定的对象实例。两个线程无法在同一对象实例上访问相同的synchronized方法。一个将获得锁,另一个将阻塞,直到第一个线程离开该方法。

在您的示例中,实例方法在包含它们的对象上同步。在这种情况下,当您调用alphonse.bow(...)时,您将锁定在alphonse对象上。 gaston.bow(...)锁定gaston

您可以通过两种方法来获取一个对象的多个实例以锁定同一对象。

  • 您可以将方法设置为staticsynchronized,在这种情况下,它们将锁定在类对象本身上。每个类加载器仅这些对象之一。
    public static synchronized void bow(Friend bower) {
    
  • 它们都可以锁定已定义的静态对象。就像是:
    private static final Object lockObject = new Object();
    ...
    public void bow(Friend bower) {
        synchronized (lockObject) {
            ....
        }
    }
    
  • 或者,如果您不想将其设为静态,则可以传入该对象以进行锁定。


  • 您的输出可能类似于以下内容:
  • (可能)首先启动gaston线程,然后调用bow(alphonse)
  • 这将锁定gaston对象并输出:Gaston: Alphonse has bowed to me!
  • 它调用alphonse.bowBack(this)
  • 此调用将锁定alphonse对象并输出:Alphonse: Gaston has bowed back to me!
  • alphonse.bowBack(this)退出,解锁alphonse对象。
  • gaston.bow(alphonse)退出,解锁gaston对象。
  • ,然后gaston线程退出。
  • (可能)接下来启动alphonse线程,并调用bow(gaston)
  • 这将锁定alphonse对象并输出:Alphonse: Gaston has bowed to me!
  • 它调用gaston.bowBack(this)
  • 此调用将锁定gaston对象并输出:Gaston: Alphonse has bowed back to me!
  • gaston.bowBack(this)退出,解锁gaston对象。
  • alphonse.bow(gaston)退出,解锁alphonse对象。

  • 这可能会以许多不同的顺序发生。 alphonse线程可以首先运行,即使它的start()方法在以后被调用。如果alphonse.bow(...)当前正在运行,那么锁将使您从中唯一摆脱的是对alphonse.bowBack(...)的调用。正如@ user988052指出的那样,因为每个线程都锁定自己的对象,然后尝试锁定另一个对象,所以很容易会出现死锁。

    10-05 19:18