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
。
您可以通过两种方法来获取一个对象的多个实例以锁定同一对象。
static
和synchronized
,在这种情况下,它们将锁定在类对象本身上。每个类加载器仅这些对象之一。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指出的那样,因为每个线程都锁定自己的对象,然后尝试锁定另一个对象,所以很容易会出现死锁。