死锁和同步方法

发布于 2024-11-14 04:48:07 字数 1035 浏览 1 评论 0原文

我在 Stack Overflow 上找到了一段代码,我认为它与我所面临的非常相似,但我仍然不明白为什么这会陷入僵局。该示例取自 Java 中的死锁检测

Class A
{
  synchronized void methodA(B b)
  {
    b.last();
  }

  synchronized void last()
  {
    System.out.println(“ Inside A.last()”);
  }
}

Class B
{
  synchronized void methodB(A a)
  {
    a.last();
  }

  synchronized void last()
  {
    System.out.println(“ Inside B.last()”);
  }
}

Class Deadlock implements Runnable 
{
  A a = new A(); 
  B b = new B();

  // Constructor
  Deadlock()
  {
    Thread t = new Thread(this); 
    t.start();
    a.methodA(b);
  }

  public void run()
  {
    b.methodB(a);
  }

  public static void main(String args[] )
  {
    new Deadlock();
  }
}

在本例中,当调用 Deadlock() 构造函数时,它以线程的形式启动。当它执行此操作时,将调用 run() 方法。它将调用 b.methodB(a),然后调用 a.last() 来打印一条语句。同时,a.methodA(b) 会调用 b.last()。任何对象都没有交叉依赖,并且它们也不会同时执行方法。即使它们是,synchronized 关键字也会将它们排队,不是吗?但为什么有时也会陷入僵局呢?并非总是如此,但有时会陷入僵局,这是不可预测的。是什么原因导致这个问题陷入僵局以及解决方法?

I've found one of the code on Stack Overflow and I thought it is pretty similar to what I am facing but I still don't understand why this would enter a deadlock. The example was taken from Deadlock detection in Java:

Class A
{
  synchronized void methodA(B b)
  {
    b.last();
  }

  synchronized void last()
  {
    System.out.println(“ Inside A.last()”);
  }
}

Class B
{
  synchronized void methodB(A a)
  {
    a.last();
  }

  synchronized void last()
  {
    System.out.println(“ Inside B.last()”);
  }
}

Class Deadlock implements Runnable 
{
  A a = new A(); 
  B b = new B();

  // Constructor
  Deadlock()
  {
    Thread t = new Thread(this); 
    t.start();
    a.methodA(b);
  }

  public void run()
  {
    b.methodB(a);
  }

  public static void main(String args[] )
  {
    new Deadlock();
  }
}

In this case, when the Deadlock() constructor is called, it starts itself as a thread. When it does this, the run() method is invoked. It will call b.methodB(a), which then calls a.last() to just print out a statement. At the same time, a.methodA(b) would call b.last(). There is no cross dependencies on any object and they are not executing a method at a same time too. Even if they are, the synchronized keyword would queue them, wouldn't it? But how come this would occasionally enter a deadlock too? It is not all the time but it would sometimes enter a deadlock, which is quite unpredictable. What is it that causes this to go into a deadlock and workarounds?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

爱*していゐ 2024-11-21 04:48:07

这两条语句的执行可能是交织的:

Thread 1:  a.methodA(b);    //inside the constructor
Thread 2:  b.methodB(a);    //inside run()

要执行 a.methodA(),线程 1 需要获取 A 对象上的锁。

要执行 b.methodB(),线程 2 需要获取 B 对象上的锁。

为了使线程 1 的 methodA() 能够调用 b 实例上的同步方法,它需要获取 b 上的锁被线程 2 持有,这将导致线程 1 等待,直到该锁被释放。

为了使 Thread2 的 methodB() 能够调用 a 实例上的同步方法,它需要获取 a 上持有的锁由线程 1 执行 - 这也会导致线程 2 等待。

由于每个线程都持有另一个线程想要的锁,因此如果两个线程都无法获得它想要的锁,并且两个线程都不会释放它所持有的锁,就会发生死锁。

重要的是要理解,此代码在运行时不会 100% 产生死锁 - 仅当四个关键步骤(线程 1 持有 A 的锁并尝试获取 B,线程 2 持有 B 的锁并尝试获取 A 的锁)时才会产生死锁。是按照一定的顺序执行的。运行此代码足够多次,但该顺序必然会发生。

It is possible that the execution of these two statements is interweaved:

Thread 1:  a.methodA(b);    //inside the constructor
Thread 2:  b.methodB(a);    //inside run()

to execute a.methodA(), Thread 1 will need to obtain the lock on the A object.

to execute b.methodB(), Thread 2 will need to obtain the lock on the B object.

For Thread 1's methodA() to then be able to call the sychronized method on the b instance, it will need to obtain the lock on b being held by Thread 2, which will cause Thread 1 to wait until that lock is freed.

For Thread2's methodB() to be able to call the synchronized method on the a instance, it will need to obtain the lock being held on a by Thread 1 - which will cause Thread 2 to wait as well.

Since each thread is holding a lock that the other thread wants, a deadlock will occur where neither thread is able to obtain the lock it wants, and neither thread will release the locks that it does hold.

It's important to understand that this code will not produce a deadlock 100% of the time you run it - only when the four crucial steps (Thread1 holds A's lock and tries to obtain B, which Thread 2 holds B's lock and tries to obtain A's) are executed in a certain order. Run this code enough times and that order is bound to happen though.

抱着落日 2024-11-21 04:48:07

synchronized 在方法或代码块执行之前必须获取的对象上放置了一个锁。因为它锁定整个对象,所以它是一个不优雅的工具,有时看起来很容易使用,但会产生这样的死锁,即没有实际有争议的数据被读取或写入。

a.method(b) 锁定 a 对象。 b.method(a) 锁定 b 对象。并且两个执行线程都无法继续调用 b.last()a.last(),因为它们都在等待另一个对象释放其锁。

synchronized places a lock on the object that must be acquired before the methods or codeblocks can execute. Because it locks entire objects, it is an inelegant tool that sometimes looks pretty easy to use, but gives deadlocks like this, where no actual contested data is being read or written.

a.method(b) locks the a object. b.method(a) locks the b object. And neither thread of execution can continue on to calling b.last() or a.last(), because they are both waiting for the other object to release its lock.

遇见了你 2024-11-21 04:48:07

调用methodA(有效)执行lock(a)、lock(b)。
如果任务随后切换并尝试方法B,它就会立即命中lock(b)。

Calling methodA does (effectively) lock(a), lock(b).
If the task switches then and tries methodB, it hits lock(b) right then.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文