如何在下面的代码中发生死锁?

时间:2015-05-28 15:02:36

标签: java

我有一个简单的代码来测试死锁

public class ClassB {
    public synchronized void fooB(Classs A) throws InterruptedException{
        System.out.print("Thread : " + Thread.currentThread().getName()+ " entered to fooB \n");
        Thread.sleep(1000);
        System.out.print("ClassB locked the fooA \n");
        A.lastA();

    }

    public synchronized void lastB(){
        System.out.print("I am lastB \n");
    }
}

另外我还有另一个名为ClassA的课程:

public class ClassA {
    public synchronized void fooA(ClassB B) throws InterruptedException{
        System.out.print("Thread : " + Thread.currentThread().getName()+ " entered to fooA \n");
        Thread.sleep(1000);
        System.out.print("ClassA locked the fooB \n");
        B.lastB();
    }

    public synchronized void lastA(){
        System.out.print("I am lastA \n");
    }    
}

所以,现在我有另一个代码调用这些类并导致死锁,如下所示:

public class DeadLockTest implements Runnable {
    ClassA ca=new ClassA();
    ClassB cb=new ClassB();

    public DeadLockTest() throws InterruptedException{
        new Thread(this).start();
        ca.fooA(cb);
    }

    public void run() {
        try {
             cb.fooB(ca);
        } catch (InterruptedException ex) { ....

        }
    }
}

正如您所看到的,第一个线程使用 ca.fooA(cb)锁定fooB,第二个线程使用 cb.fooB(ca)锁定fooA没有人对lastA和lastB方法有任何锁定。这意味着这些方法应该可用,但它们不可用。为什么?线程刚刚锁定了fooA和fooB。那么,为什么例如第一个线程不能使用lastB()而第二个线程无法访问lastA()而这两个方法没有锁定?

3 个答案:

答案 0 :(得分:11)

在方法上使用时,synchronized关键字会隐式锁定this - 在与this关联的监视器上。物体有监视器;方法没有。因此,用于fooA()的监视器lastA()上使用的监视器相同。这就是你陷入僵局的原因。

请在继续之前阅读synchronized ...

答案 1 :(得分:3)

这看起来相当直接。这是典型的循环共享资源场景。 A需要B继续,B需要A继续。

锁:

Thread 1 -> ClassB -> ClassA
Thread Main -> ClassA -> ClassB

处理订单:

  1. 主要线程,您启动一​​个新线程线程A
  2. 线程A 获取 ClassB
  3. 的锁定
  4. Thread Main 获取 ClassA
  5. 的锁定
  6. 线程A 请求锁定并阻止锁定 ClassA
  7. Thread Main 请求锁定并阻止锁定 ClassB的

答案 2 :(得分:0)

您正在同步方法,因此锁定对象是每种情况下的对象(ca和cb)。

当线程调用cb.fooB(ca)时,它会抓取锁定对象cb。

然后主线程调用ca.fooA(cb),因此抓住锁定对象ca。

但是,fooA方法在主线程中调用cb.lastB(),并且此方法也是同步的,因此主线程尝试获取锁定cb,只发现另一个线程具有已经锁定,所以必须等待。

与此同时,另一个线程调用了cb.fooB(ca),后者又调用ca.lastA(),所以试图抓住ca上的锁,只发现主线程已经有锁,所以它也必须等待。

结果:每个线程都有一个锁,另一个需要继续,所以他们互相等待。死锁。