Java死锁代码解释

Java死锁代码解释,java,multithreading,Java,Multithreading,有人能解释一下为什么下面的代码会导致死锁吗。 我的理解是,当alphonse(线程)运行时,它会获取friend obj上的锁,因为它调用了bow()方法,但是为什么gaston(另一个线程)能够获取同一个friend obj上的锁,而alphonse没有完成/释放friend obj上的锁呢。 }想象两个线程并行执行: thread1 thread2 ----------------------------------- ---

有人能解释一下为什么下面的代码会导致死锁吗。 我的理解是,当alphonse(线程)运行时,它会获取friend obj上的锁,因为它调用了bow()方法,但是为什么gaston(另一个线程)能够获取同一个friend obj上的锁,而alphonse没有完成/释放friend obj上的锁呢。


}

想象两个线程并行执行:

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()
此时,两个线程都在等待另一个线程释放锁,并且两个线程都无法完成同步方法以释放锁(因为它正在等待另一个线程)

  • 螺纹1:
    alphonse.bow()
    。为了进入这个方法,线程1获取alphonse的锁,因为
    bow()
    方法是同步的
  • 螺纹2:
    gaston.bow()
    。为了进入这个方法,线程2获取加斯顿锁,因为
    bow()
    方法是同步的
  • 螺纹1:
    gaston.bowBack()
    。要进入此方法,线程1需要获取gaston锁,因为
    bowBack()
    方法是同步的。它等待线程2释放gaston的锁
  • 螺纹2:
    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
            }
        }
    }