Java死锁代码解释
有人能解释一下为什么下面的代码会导致死锁吗。 我的理解是,当alphonse(线程)运行时,它会获取friend obj上的锁,因为它调用了bow()方法,但是为什么gaston(另一个线程)能够获取同一个friend obj上的锁,而alphonse没有完成/释放friend obj上的锁呢。Java死锁代码解释,java,multithreading,Java,Multithreading,有人能解释一下为什么下面的代码会导致死锁吗。 我的理解是,当alphonse(线程)运行时,它会获取friend obj上的锁,因为它调用了bow()方法,但是为什么gaston(另一个线程)能够获取同一个friend obj上的锁,而alphonse没有完成/释放friend obj上的锁呢。 }想象两个线程并行执行: thread1 thread2 ----------------------------------- ---
}想象两个线程并行执行:
thread1 thread2
----------------------------------- -----------------------------------
enter alphonse.bow(gaston) enter gaston.bow(alphonse)
- acquire lock on alphonse - acquire lock on gaston
gaston.bowBack(alphonse) alphonse.bowBack(gaston)
- try to acquire lock on gaston; - try to acquire lock on alphonse;
blocked because of gaston.bow() blocked because of alphonse.bow()
此时,两个线程都在等待另一个线程释放锁,并且两个线程都无法完成同步方法以释放锁(因为它正在等待另一个线程)
alphonse.bow()
。为了进入这个方法,线程1获取alphonse的锁,因为bow()
方法是同步的gaston.bow()
。为了进入这个方法,线程2获取加斯顿锁,因为bow()
方法是同步的gaston.bowBack()
。要进入此方法,线程1需要获取gaston锁,因为bowBack()
方法是同步的。它等待线程2释放gaston的锁alphonse.bowBack()
。要进入此方法,线程2需要获取alphonse的锁,因为bowBack()
方法是同步的。它等待线程1释放alphonse的锁这两个线程最终会互相等待。这是一个死锁。您有一个循环锁链: 阿方斯。鲍获得了阿方斯的锁,然后试图对付加斯顿,而加斯顿可能已经被抓住了。 加斯顿。鲍获得了加斯顿的锁,然后试图对付阿尔方斯,但已经被抓住了 要对此进行分析/可视化,请绘制线程(比如两个圆)和资源(比如两个矩形)的图表。当线程请求资源时,从线程到资源绘制一个箭头。授予资源后,从该资源向所有者线程绘制一个箭头。 只要没有循环,一切都很好。 如果您最终得到一个循环,那么您需要牺牲该循环中的某些东西来打破循环这是典型的死锁场景:您有N个对象,其中每个对象都有自己的锁,并且您以随机顺序获得多个锁 当两个踏板试图相互“鞠躬”时,就会出现问题。每个线程为自己的人(阿尔方斯和加斯顿)获得锁,然后试图在仍然为自己的人持有锁的情况下获得朋友的锁 这可以通过不同的方式解决 最简单的方法是通常使用全局锁(例如,在Friend类中定义的静态锁定对象)。这通常只允许一条螺纹一次执行弓/弓背序列。有时这很好,有时这可能是性能瓶颈 更复杂的解决方案是确保以确定的顺序获得锁,例如,确保始终在获得加斯顿锁之前获得阿尔方斯锁。因此,您可以为要锁定的对象引入一个排序标准,为简单起见,让我们假设我们可以依赖于朋友的名称是唯一的 这使得实现有点复杂,但允许比全局锁更多的并发性,同时仍然避免死锁。与盲目地在“自我”上同步不同,该方法现在决定了在谁身上同步的优先级顺序:
public void bow(Friend bower) {
// determine locking order
Friend first, second;
if (getName().compareTo(bower.getName()) > 0) {
first = this;
second = bower;
} else {
first = bower;
second = this;
}
synchronized (first) {
synchronized (second) {
// perform bow normally
}
}
}
这是因为无论alphonse向gaston鞠躬还是向gaston鞠躬,他们都会以相同的顺序获得锁。您正在类的实例上进行同步。您应该在类中声明的
静态final
字段上进行同步,该字段将等待该类的所有实例。@Luiggi Mendoza您是指bower.bowBack(这个)?不,我是指公共同步void yourMethod
@jtahlborn,至少我学到了一些东西too@jtahlborn,这不是我的家庭作业,我正在阅读oracle教程中的java代码,并试图理解其中的原因。我不是要求代码或更正,而是了解如何获取监视器锁。
public void bow(Friend bower) {
// determine locking order
Friend first, second;
if (getName().compareTo(bower.getName()) > 0) {
first = this;
second = bower;
} else {
first = bower;
second = this;
}
synchronized (first) {
synchronized (second) {
// perform bow normally
}
}
}