这是 java 文档中有关死锁的教程。我不知道线程在哪里被阻塞。因为它是同步的,所以我认为只有一个线程会进入 bow。但两人都鞠躬。 [等待[但什么时候?]]
那问题出在哪里呢?
当我添加注释时 [打印要跟踪的语句]。没有僵局。怎么办?
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() {
@Override
public void run() {
// System.out.println("Thread 1");
alphonse.bow(gaston);
// System.out.println("Th: gaston bowed to alphonse");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// System.out.println("Thread 2");
gaston.bow(alphonse);
// System.out.println("2.gaston waiting alph bowed");
}
}).start();
}
}
输出是:
Alphonse: Gaston has bowed to me!
Gaston: Alphonse has bowed to me!
没有人回头!
最佳答案
这里有两件重要的事情需要理解:1) 每个并发运行的线程在做什么? 2) 涉及哪些锁?
首先,您创建了 Friend 类的两个实例:alphonse 和 gaston。这些对象中的每一个都拥有自己的锁。所以有两种锁:alphonse 的锁和gaston 的锁。当您进入对象的同步方法时,它会锁定该对象的锁。当同步方法返回时,锁被释放(解锁)。
现在是线程。您的第一个线程,我们称它为 Alphone 的线程(注意大写 A 以区分线程和对象 alphonse)执行以下操作:(“A:”表示这是 Alphonse 的线程。)
A: alphonse.bow(gaston) - acquires alphonse's lock
A: gaston.bowBack(alphonse) - acquires gaston's lock
A: both methods return, thus releasing both locks
同时,Gaston 的线程执行此操作:(“G:”表示这是 Gaston 的线程。)
G: gaston.bow(alphonse) - acquires gaston's lock
G: alphonse.bowBack(gaston) - acquires alphonse's lock
G: both methods return, thus releasing both locks
现在我们可以将这两个信息放在一起得出我们的答案。线程可以以不同的顺序交错(即,它们的事件发生)。例如,如果事件按以下顺序发生,则会发生死锁:
A: alphonse.bow(gaston) - acquires alphonse's lock
G: gaston.bow(alphonse) - acquires gaston's lock
G: attempts to call alphonse.bowBack(gaston), but blocks waiting on alphonse's lock
A: attempts to call gaston.bowBack(alphonse), but blocks waiting on gaston's lock to
在这种情况下,每个线程都被阻塞,等待获取另一个线程持有的锁。但是,两个线程都不会释放它持有的锁,因为它必须完成它的方法才能这样做,而它不能这样做,因为它被阻塞在等待另一个线程。因此它们被卡在原地——死锁。
但是,另一种可能的交错(事件顺序)是其中一个线程在另一个线程真正开始之前完成,如下所示:
A: alphonse.bow(gaston) - acquires alphonse's lock
A: gaston.bowBack(alphonse) - acquires gaston's lock
A: both methods return, thus releasing both locks
G: gaston.bow(alphonse) - acquires gaston's lock
G: alphonse.bowBack(gaston) - acquires alphonse's lock
G: both methods return, thus releasing both locks
在这种情况下没有死锁。当您添加 println 并且没有出现死锁时,很可能发生的情况是额外的 println 的额外延迟会影响线程运行的调度和/或速率,因此您会得到这种交错而不是死锁。
当结果取决于并发事件的顺序(即它们的调度或它们运行的速率)时,称为“竞争条件”。例如,在这个程序中,哪个线程首先打印输出取决于它们的调度顺序或它们运行的速率。线程是否死锁也取决于此。因此,通过扰乱该速率(例如,通过添加额外的指令),您可能会影响比赛的结果 - 但这并不意味着比赛已经结束。
并非所有竞争条件都有可能导致死锁。然而,根据我的经验,死锁只发生在竞争条件下。 (也许知道的人可以评论一下是否必然如此,或者只是普遍如此?)
死锁一开始不容易理解;我已尽力解释,但如果您对我的帖子有任何后续问题,请告诉我。 :)
关于java - 死锁在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17396963/