死锁和同步方法

时间:2011-06-07 02:19:53

标签: java multithreading synchronization deadlock

我在Stack Overflow上找到了一个代码,我认为它与我面临的非常相似,但我仍然不明白为什么会出现这种情况。该示例来自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();
  }
}

在这种情况下,当调用Deadlock()构造函数时,它会自动作为线程启动。执行此操作时,将调用run()方法。它将调用b.methodB(a),然后调用a.last()来打印出一个语句。同时,a.methodA(b)将调用b.last()。任何对象都没有交叉依赖关系,并且它们也没有同时执行方法。即使它们是,synchronized参数也会排队,不是吗?但是为什么偶尔也会陷入僵局呢?它不是所有的时间,但它有时会进入僵局,这是非常不可预测的。是什么导致这种情况陷入僵局并解决了问题?

3 个答案:

答案 0 :(得分:18)

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

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实例上调用sychronized方法,它将需要获取线程2持有的b上的锁定,这将是导致线程1等待,直到释放该锁。

对于Thread2的methodB()能够在a实例上调用synchronized方法,它将需要获取线程1在a上保持的锁定 - 这将导致线程2等待。

由于每个线程都持有另一个线程想要的锁,因此会发生死锁,其中任何一个线程都无法获得所需的锁,并且两个线程都不会释放 所持有的锁

重要的是要理解这个代码在100%运行时不会产生死锁 - 只有当四个关键步骤(Thread1持有A的锁并尝试获取B,线程2持有B的锁并尝试获得A')按特定顺序执行。运行此代码足够多次,但订单肯定会发生。

答案 1 :(得分:2)

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

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

答案 2 :(得分:0)

调用方法A(有效地)锁定(a),锁定(b)。 如果任务然后切换并尝试methodB,则它会立即锁定(b)。