如何在给定的Java程序中出现死锁?

时间:2014-03-07 13:21:30

标签: java synchronization deadlock

以下代码段取自Java Tutorials,表示线程永远被阻止,但我无法弄清楚如何。请解释一下。

这两个同步方法是否共享同一个内部锁?

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

5 个答案:

答案 0 :(得分:3)

在上面的示例中,可能存在以下情况:

alphonse has his own lock
gaston has his own lock

因为在自己的线程中使用自己的锁调用bow()方法。如果你仔细看,在bow()方法中,alphonse现在使用另一个引用调用bowback(),即使用gaston的锁。

所以,可能有一种情况,gaston已经使用他自己的锁进入bow()方法,但是alphonse的线程试图输入已经被gaston的线程锁定的bowback()方法。反之亦然。

因此,调用bowback()方法的引用的反转是容易出错的,这可能会导致死锁。

   public synchronized void bow(Friend bower) {
        System.out.format("%s: %s"
            + "  has bowed to me!%n", 
            this.name, bower.getName());
        bower.bowBack(this); // <---------  This Line 
        // here bower is not the same person how acquired
        // the lock while calling bow() method
    }

答案 1 :(得分:0)

是的,这两种方法都有相同的锁(我猜对象本身),因为它们表示here

  

当一个线程正在为对象执行同步方法时,全部   调用同一对象的同步方法的其他线程   块

答案 2 :(得分:0)

在一个Thread中,来自方法bow的上下文在其他Thread的上下文中被称为方法,这就是问题。

对于Alphonse和Gaston来说,这个对象是不同的,并且在两个线程中依次对这两个线程进行同步。进入的第一个线程将进行第一次锁定并尝试获取第二个,但是由于其他线程被其他线程占用,它将被停止。

如果一个Thread等待其他人完成完整计算,则不会出现问题。

答案 3 :(得分:0)

线程A在bow(gaston)时获取alphonse锁 线程B在bow(aphonse)时获取gaston锁 线程A在bowBack(gaston)时等待锁定 线程B在bowBack(aphonse)

时等待锁定

答案 4 :(得分:0)

从您的链接:

  

当死锁运行时,两个线程在尝试时都很可能会阻塞   调用bowBack。这两个块都不会结束,因为每个线程都在等待另一个线程退出弓。

什么是死锁?

通常,当线程(1)锁定资源(A)然后尝试锁定另一个资源(B)时会发生死锁,但资源B被锁定从另一个尝试锁定资源A的线程(2)。

在这种情况下,没有线程可以访问这两个资源,并且会一直等到资源空闲。

无论如何,杰米注意到如果你运气好的话就不会发生僵局,但是有了i7我会得到这个

Alphonse: Gaston  has bowed to me!
Gaston: Alphonse  has bowed to me!

请记住方法中的synchronized表示synchronized(this)

@Nikita Rybak回答同一个问题(Java deadlock question)(赞成他的回答!)

  1. 输入alphonse.bow(gaston);, alphonse现已因同步关键字而被锁定
  2. 输入gaston.bow(alphonse);, gaston现已锁定
  3. 不能执行bower.bowBack(this);从第一个弓方法调用,因为gaston(凉亭)被锁定。等待锁被释放。
  4. 不能执行bower.bowBack(this);从第二弓方法调用,因为alphonse(凉亭)被锁定。等待锁被释放。
  5. 其他答案:

    How this java code produces deadlock?

    Java deadlock question