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

2022-09-03 10:02:37
    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();
    }
}

当我运行这个程序时,我得到的输出是

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

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


答案 1

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

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

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

有几种方法可以使一个对象的多个实例锁定在同一个对象上。

  • 您可以使该方法成为,在这种情况下,它们将锁定类对象本身。每个类装入器只有一个这样的对象。staticsynchronized

    public static synchronized void bow(Friend bower) {
    
  • 它们都可以锁定定义的静态对象。像这样:

    private static final Object lockObject = new Object();
    ...
    public void bow(Friend bower) {
        synchronized (lockObject) {
            ....
        }
    }
    
  • 或者,如果您不想将其设置为静态,则可以传入要锁定的对象。

您的输出可能如下所示:

  1. 线程(可能)首先启动并调用gastonbow(alphonse)
  2. 这将锁定对象并输出:gastonGaston: Alphonse has bowed to me!
  3. 它调用 .alphonse.bowBack(this)
  4. 此调用锁定对象并输出:alphonseAlphonse: Gaston has bowed back to me!
  5. alphonse.bowBack(this)退出,解锁对象。alphonse
  6. gaston.bow(alphonse)退出,解锁对象。gaston
  7. 然后线程退出。gaston
  8. 线程 (可能) 开始下一个并调用alphonsebow(gaston)
  9. 这将锁定对象并输出:alphonseAlphonse: Gaston has bowed to me!
  10. 它调用 .gaston.bowBack(this)
  11. 此调用锁定对象并输出:gastonGaston: Alphonse has bowed back to me!
  12. gaston.bowBack(this)退出,解锁对象。gaston
  13. alphonse.bow(gaston)退出,解锁对象。alphonse

这可能以许多不同的顺序发生。线程可以首先运行,即使它的方法在稍后被调用。锁唯一能省去您的是调用 if 当前正在运行。正如@user988052所指出的,由于每个线程都锁定自己的对象,然后尝试锁定另一个对象,因此很容易出现死锁。alphonsestart()alphonse.bow(...)alphonse.bowBack(...)


答案 2

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

是和否:

  • 是的,如果在类的不同实例上调用该方法。

  • 不可以,两个线程不能同时在类的同一实例调用同步的方法。即使两个线程调用不同的方法(只要实例相同),情况也是如此。