【问题标题】:How is deadlock occuring in the below code?下面的代码是如何发生死锁的?
【发布时间】:2014-11-25 12:21:20
【问题描述】:

我试图从 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();

我试图从没有以死锁情况结束的弓形程序中删除同步关键字,即程序执行完成并且程序在执行后终止。

谢谢

【问题讨论】:

    标签: concurrency deadlock


    【解决方案1】:

    每个对象都有一个与之关联的锁,也称为隐式锁或监视器锁。当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 中删除“同步”可以防止死锁,正如您所发现的,因为现在没有什么可以阻止 alphonse 线程调用 gaston 的 bowBack 方法 - alphonse 不再需要获取 gaston 对象锁持有。同样的逻辑反过来适用于gaston,他也可以继续前进。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 这是错误的:“由于类 Friend 是静态的,所以类 Friend 的方法是静态的” 该类是静态的,因此我们可以在同一个文件中拥有多个类。如果Friend 在它自己的Friend.java 文件中而不是静态的,死锁仍然会发生
      • @dkatzel 谢谢。不知道java的静态类概念。
      猜你喜欢
      • 2017-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多