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();
}
}
当我运行这个程序时,我得到输出为
阿方斯:加斯顿向我鞠躬致敬! 加斯顿:阿尔方斯向我鞠躬!
两个线程可以同时访问同步方法吗?
答案 0 :(得分:12)
两个线程可以同时访问同步方法吗?
这取决于两个线程试图锁定的对象实例。两个线程无法在同一对象实例上访问相同的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所指出的那样,因为每个线程锁定自己的对象,然后尝试锁定另一个,所以很容易出现死锁。
答案 1 :(得分:10)
两个线程可以同时访问同步方法吗?
是和否:
是的,如果在该类的不同的实例上调用该方法。
不,两个线程不能同时调用类的同一实例上的同步方法。即使两个线程调用不同的方法(只要实例是相同的),情况也是如此。
答案 2 :(得分:2)
我没有详细检查您的代码,但我认为我认识到如何创建死锁的 典型示例。
但是你不应该只调用一次来尝试创建死锁。
在循环中创建线程,你很可能会陷入僵局:
for ( int i = 0; i < 1000; i++ ) {
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();
}
请注意,您不会使2000个线程死锁:只有部分线程会死锁。您可以通过获取程序/ JVM的一个线程来验证这一点。
答案 3 :(得分:1)
使用synchronized关键字,您可以锁定实例方法的实例,也可以锁定静态方法的类。所以在这里你保证在给定的时间最多一个线程在给定的实例上执行bow或bowBack(如果一个线程执行bow,没有其他线程可以执行bowBack,因为两个方法在同一个锁上同步)...
还有一条评论:一旦线程获得锁定,锁就会重入,它可以输入同一锁上同步的其他方法。
答案 4 :(得分:1)
如Deadlock Tutorials 中所述,此代码来自,此代码通常会阻止。
当Deadlock运行时,两个线程在尝试调用bowBack时极有可能会阻塞。这两个块都不会结束,因为每个线程都在等待另一个线程退出弓。