死锁 - 在这个例子中它是如何发生的?



谁能解释一下:

  1. 为什么会出现僵局?
  2. 加斯顿如何在艾尔冯斯退出该功能之前进入功能弓?(它应该从函数bowBack()返回以退出函数bow()- OR(?

这是我得到的输出 - 然后程序卡住了!

艾尔冯斯:"加斯顿向我鞠躬了!

加斯顿: 艾尔冯斯向我鞠躬了!

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块/方法同步到this,即块/方法调用的对象实例。(对于static"对象实例"将替换为"类实例"。

也就是说,您的 2 个对象与自身同步,而不是一个公共对象。

尝试这样的事情:

public class Deadlock {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void bow(Friend bower) {
synchronized (getClass()) {
System.out.format("%s: %s  has bowed to me!%n", this.name, bower.getName());
bower.bowBack(this);
}
}
public void bowBack(Friend bower) {
synchronized (getClass()) {
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:alphonse实例被锁定,alphonse.bow(gaston);打印一行然后调用gaston.bowBack()(但由于下面调用的实例同步bow()gaston线程 2 被锁定(

线程 2:gaston实例被锁定,gaston.bow(alphonse);打印一行然后调用alphonse.bowBack()(但由于同步bow()实例调用alphonse线程 1 被锁定(

所以他们都在等待发布并且无法退出bow()方法,因此死锁

首先,同步用法是错误的。预言机教程很好地指出:

首先,对同一对象上的同步方法进行两次调用不可能交错。

正如另一个答案所解释的:示例中显示的代码不使用"公共锁"(两个不同对象上的同步方法不会影响"其他"方法调用(。

除此之外:一旦你删除了这些System.out.format()调用 - 你的程序可以(通常(不会陷入死锁。

或者:在启动线程之前,在主线程中放一个println()- 同样,程序不会死锁。

换句话说:打印到控制台非常耗时。因此,这会极大地影响线程的时间!这里发生的情况是,大部分时间都花在这些控制台输出操作上。有关甚至使用相同的名称的类似问题,请参阅此处;-(

在你的例子中发生了什么:

  1. 线程阿尔方斯正在通过输入功能bow来获取阿尔方斯的锁。

  2. 线程加斯顿
  3. 正在通过输入功能bow来获取加斯顿的锁。

  4. 线程阿尔方斯正在向加斯顿请求锁以进入功能bowBack但该锁目前由线程加斯顿持有,因此艾尔方斯被迫等待。

  5. 线程加斯顿正在向阿尔方斯请求锁以进入功能bowBack但该锁目前由线程阿尔方斯持有,因此加斯顿被迫等待。

死锁。

为什么会这样:

synchronized函数是synchronized(this) { ... }的句法糖 所以上面的类也可以这样写:

public void bow(Friend bower) {
synchronized (this) {
System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName());
bower.bowBack(this);
}
}
public void bowBack(Friend bower) {
synchronized (this) {
System.out.format("%s: %s has bowed back to me!%n", this.name, bower.getName());
}
}

但是,此示例中的this是类的实例,因此每个实例都有其单独的锁。如果要在类的所有实例中锁定同一对象,则需要锁定如下所示的静态对象:

protected static final Object STATIC_LOCK = new Object();
public void bow(Friend bower) {
synchronized (STATIC_LOCK) {
System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName());
bower.bowBack(this);
}
}
public void bowBack(Friend bower) {
synchronized (STATIC_LOCK) {
System.out.format("%s: %s has bowed back to me!%n", this.name, bower.getName());
}
}

由于此LOCK对象是静态的,因此两个线程现在将锁定在同一对象上,因此可以正确地相互锁定。请注意在这种情况下强烈建议的关键字final,因为否则同步锁可能会在执行期间更改(通过代码中的错误或疏忽(,这会让您重新陷入死锁状态,原因与上述完全相同。

最新更新