如何在下面的代码中发生死锁?

时间:2014-11-25 12:21:21

标签: concurrency deadlock

我正在尝试从Oracle的网站deadlock了解deadlock,但不确定为什么&两个自定义线程何时进入死锁状态。

package com.geekthread.java.threads;

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");
         //holds lock for alphonse            
      new Thread(new Runnable() {
        public void run() { alphonse.bow(gaston); }
    }).start();
    //holds lock for gastone
    new Thread(new Runnable() {
        public void run() { gaston.bow(alphonse); }
    }).start();
}
}
}

请更正我对上述计划的理解: -

1。)保持对alphonse的锁定

new Thread(new Runnable() {
            public void run() { alphonse.bow(gaston); }
        }).start();

2。)保持对gastone的锁定

new Thread(new Runnable() {
                public void run() { gaston.bow(alphonse); }
            }).start();

我试图从没有在死锁情况下结束的bowback中删除synchronized关键字,即程序执行完成,程序在执行后终止。

由于

2 个答案:

答案 0 :(得分:2)

每个对象都有一个与之关联的锁,也称为隐式锁或监视器锁。当在示例中对方法使用synchronized时,线程将尝试获取与该方法的对象关联的锁。因此,运行alphonse.bow(gaston);的线程将获取与alphonse对象关联的锁。

大致在同一时间,运行gaston.bow(alphonse);的线程将获取与gaston对象关联的锁。

所以你让alphonse线程持有alphonse对象的锁,而gaston线程持有gaston对象的锁。

当alphonse现在尝试执行bower.bowBack(this);时,请注意'bower'是指gaston对象。因此alphonse正在尝试执行gaston对象的bowBack方法。由于bowBack方法是同步的,因此alphonse需要使gaston对象锁定才能继续。但当然gaston线程已经有gaston对象锁定了!

所以alphonse试图执行gaston的bowBack方法,但不能因为它无法获得gaston对象的锁定。

与此同时,加斯顿也有同样的问题。他需要调用alphonse的bowBack方法,但是alphonse线程已经有了alphonse对象锁。

因此每个线程都有一个锁,并且正在尝试获取另一个线程已经拥有的锁,并且两者都无法继续 - 这是一个典型的死锁场景..

编辑:从bowBack删除'synchronized'可以防止死锁,正如您所发现的那样,因为现在没有什么能阻止alphonse线程调用gaston的bowBack方法 - alphonse不再需要获取gaston gaston持有的对象锁。相同的逻辑适用于gaston,他也可以继续。

答案 1 :(得分:0)

我绝对不是Java方面的专家,但我的猜测是:

由于类Friend是静态的,因此类Friend的方法是静态的。因此,这些方法锁定类本身而不是类的对象。

这应提供更多见解:8.4.3.6, 'synchronized Methods'