Java 并发-为什么会出现这种死锁

Java 并发-为什么会出现这种死锁,java,multithreading,concurrency,Java,Multithreading,Concurrency,嗯。我在理解并发的基础知识方面遇到了一些困难。这个问题是关于僵局的。请告诉我为什么这两个线程都以死锁结束 我从教程中选取了这个例子。它说 当死锁运行时,两个线程在试图调用bowBack时很可能都会阻塞。两个阻塞都不会结束,因为每个线程都在等待另一个线程退出bow 我的理解是:首先,它们会等待,因为当线程调用同步方法时,它会自动获取同步方法所属对象的内在锁,并继续拥有它,直到方法返回;同时,没有其他线程可以拥有它 1。现在我的第一个问题是第一个线程调用zarah.bow(),因此内在锁与zarah

嗯。我在理解并发的基础知识方面遇到了一些困难。这个问题是关于僵局的。请告诉我为什么这两个线程都以死锁结束

我从教程中选取了这个例子。它说

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

我的理解是:首先,它们会等待,因为当线程调用同步方法时,它会自动获取同步方法所属对象的内在锁,并继续拥有它,直到方法返回;同时,没有其他线程可以拥有它

1。现在我的第一个问题是第一个线程调用zarah.bow(),因此内在锁与zarah关联。第二个线程将调用khan.bow(),这将是一个不同的内在锁(因为它与另一个名为khan的对象相关联),不是吗?

扎拉·鲍和汗·鲍不是不同吗?因为它们属于两个不同的实例?

2。第二个问题来自“两个”线程永远等待的概念。两条线将永远被阻塞,等待对方退出弓。我不明白。

package Threads;

public class DeadlockModified {
    static class Friend {
        private final String name;
        Friend(String name){
            this.name=name;
        }
        private String getName(){
            return this.name;
        }
        private synchronized void bow(Friend bower){
            System.out.format("%s: %s"+" bowed to me.%n",bower.getName(),name); 
            bower.bowBack(this);
        }
        private synchronized void bowBack(Friend bower){
            System.out.format("%s: %s" + " was nice enough to bow back to me.%n",bower.getName() ,name );
        }
    }
    public static void main(String [] args){
        final Friend zarah= new Friend("Zarah");
        final Friend khan= new Friend("Khan");
        new Thread(new Runnable(){
            public void run(){zarah.bow(khan);}
        }).start();
        new Thread(new Runnable() {
            public void run(){khan.bow(zarah);}
        }).start();
    }
}
输出:-

Khan: Zarah bowed to me.
Zarah: Khan bowed to me.
先谢谢你

编辑:-

在本教程的“同步方法”一节中,作者写道

“从同步代码调用其他对象的方法可能会产生问题,这些问题将在“活动性”一节中介绍。”

这是关于活力的部分。我看到另一个对象的方法bowBack()正在从bow()调用。还有一些问题-查看程序的输出,看起来两个线程都没有执行bowBack()。但是没有给出更多的细节。

  • 线程1调用
    zarah.bow(khan)
    :它获取
    zarah
  • 线程2调用
    khan.bow(zarah)
    :它获取
    khan
  • 线程1试图调用
    khan.bowBack()
    :它需要khan的内在锁才能做到这一点。但是这个锁由线程2持有。因此线程1等待线程1释放khan的锁
  • 线程2尝试调用
    zarah.bowBack()
    :它需要zarah的内在锁才能做到这一点。但是这个锁由线程1持有。因此线程2等待线程1释放zarah的锁
因此,两条线程都在等待对方,永远。这是一个僵局。

  • 线程1调用
    zarah.bow(khan)
    :它获取
    zarah
  • 线程2调用
    khan.bow(zarah)
    :它获取
    khan
  • 线程1试图调用
    khan.bowBack()
    :它需要khan的内在锁才能做到这一点。但是这个锁由线程2持有。因此线程1等待线程1释放khan的锁
  • 线程2尝试调用
    zarah.bowBack()
    :它需要zarah的内在锁才能做到这一点。但是这个锁由线程1持有。因此线程2等待线程1释放zarah的锁
因此,两条线程都在等待对方,永远。这是一个僵局

zarah.bow()和khan.bow()不一样吗

是的,对
bow()
的调用在不同的实例上执行,但在内部,它们在另一个实例上调用
bowBack()
,并且该调用也是同步的

示例:
zarah.bow()
将同步
zarah
(即调用它的实例)以及
bower.bowBack(此)
在调用
khan.bow(zarah)
中,因为这也可以被理解为
zarah.bowBack(khan)
bower=zarah
this=khan

两条线将永远被阻塞,等待对方退出弓

如果没有任何机制来中断其中一个线程,那么两个线程都将等待另一个线程离开同步部分,并且由于它们都在自己的同步块中等待,因此它们永远不会离开

关于死锁的一个很好的非技术性例子是。每一位哲学家都是“哲学家”类的“实例”,在等待其他人释放他们在叉子上的锁的同时,会在他的叉子上持有自己固有的锁

zarah.bow()和khan.bow()不一样吗

是的,对
bow()
的调用在不同的实例上执行,但在内部,它们在另一个实例上调用
bowBack()
,并且该调用也是同步的

示例:
zarah.bow()
将同步
zarah
(即调用它的实例)以及
bower.bowBack(此)
在调用
khan.bow(zarah)
中,因为这也可以被理解为
zarah.bowBack(khan)
bower=zarah
this=khan

两条线将永远被阻塞,等待对方退出弓

如果没有任何机制来中断其中一个线程,那么两个线程都将等待另一个线程离开同步部分,并且由于它们都在自己的同步块中等待,因此它们永远不会离开


关于死锁的一个很好的非技术性例子是。每个哲学家都是“哲学家”类的一个“实例”,在等待其他人释放其叉子上的锁时,会在其叉子上持有自己的固有锁。

为了确保您真正理解这一点,请尝试使用该习语重写这些方法

synchronized(Object){
enter code here
}
这将获得上的内在锁
synchronized(bower){
System.out.format("%s: %s"+" bowed to me.%n",bower.getName(),name); 
        bower.bowBack(this);
}
static class proxyLock(){};
private void bow(proxyLock lock, Friend bower){
synchronized(lock){
    System.out.format("%s: %s"+" bowed to me.%n",bower.getName(),name); 
        bower.bowBack(this);
    }
}