关于Java中死锁情况的问题

我正在学习Java中的死锁问题,并且有Sun官方教程中的示例代码:

阿尔方斯和加斯顿是朋友,也是很好的礼节。 严格的礼貌规则是,当你向朋友鞠躬时,你必须保持鞠躬,直到你的朋友有机会归还弓。 不幸的是,这条规则没有考虑到两个朋友可能同时向对方低头的可能性。

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();
    }
}

Sun的解释是:

当Deadlock运行时,两个线程在尝试调用bowBack时都会阻塞。 这两个块都不会结束,因为每个线程都在等待另一个线程退出低头。

我似乎不太喜欢。 当alphonse.bow(gaston)运行时,弓法被锁定。 所以现在它会首先打印出“加斯东向我鞠躬!”。 然后它会继续打电话给bowBack,并锁定bowback。 这怎么会导致死锁? 我误解了一个同步方法被调用时会发生什么?

如果有人能给我一个简单的解释,谢谢。


需要注意的一点是,它不是被锁定的方法,而是对象实例。

当你打电话给alphonse.bow(gaston) ,它会尝试获取alphonse的锁定。 一旦有锁,它会打印一条消息,然后调用gaston.bowBack(alphonse) 。 此时,它试图获得gaston的锁定。 一旦它有锁,它将打印一条消息,然后释放锁,最后释放alphonse上的锁。

在死锁中,锁是按照这样的顺序获取的,即任何线程都无法继续进行。

  • 线程1:获取alphonse锁定
  • 线程2:获得gaston上的gaston
  • 线程1:打印消息
  • 线程1:尝试获取gaston锁定 - 不能,因为线程2已经拥有它。
  • 线程2:打印消息
  • 线程2:尝试获取alphonse锁 - 不能,因为线程1已经拥有它。

  • 阿方斯和加斯顿是两个不同的对象。 每个对象都有一个与之关联的内部监视器(锁)。

    可能会发生这样的情况:

    alphonse被创建。 他的对象监视器是1。

    gaston被创建。 他的对象监视器是2。

    alphonse.bow(Gaston)的; alphonse现在拥有锁定#1

    gaston.bow(阿方); gaston现在拥有锁定#2

    alphonse在gaston上叫bowback并正在等待lock#2 gaston在alphonse上叫bowback并正在等待锁#1

    合理? 使用同步关键字锁定实例在方法的持续时间内监视。 这个例子可以改写如下:

    public class Deadlock {
        static class Friend {
            private final String name;
            public Friend(String name) {
                this.name = name;
            }
            public String getName() {
                return this.name;
            }
            public void bow(Friend bower) {
                synchronized(this) {            
                            System.out.format("%s: %s has bowed to me!%n", 
                        this.name, bower.getName());
                            bower.bowBack(this);
                }
            }
            public void bowBack(Friend bower) {
                synchronized(this) {
                            System.out.format("%s: %s has bowed back to me!%n",
                        this.name, bower.getName());
                }
            }
        }
    }
    

    锁定在Java对象上,而不是Java方法。 所以当在一个方法上使用synchronized时,它会锁定“this”对象。 在静态方法的情况下,它锁定类对象。

    您可以使用synchronized ( object ) { }显式指定监视器对象。

    链接地址: http://www.djcxy.com/p/91847.html

    上一篇: Question About Deadlock Situation in Java

    下一篇: How to avoid NullPointerException in if condition