我有一个简单的代码来测试死锁
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()而这两个方法没有锁定?
答案 0 :(得分:11)
在方法上使用时,synchronized
关键字会隐式锁定this
- 在与this
关联的监视器上。物体有监视器;方法没有。因此,用于fooA()
的监视器与lastA()
上使用的监视器相同。这就是你陷入僵局的原因。
请在继续之前阅读synchronized
...
答案 1 :(得分:3)
这看起来相当直接。这是典型的循环共享资源场景。 A需要B继续,B需要A继续。
锁:
Thread 1 -> ClassB -> ClassA
Thread Main -> ClassA -> ClassB
处理订单:
答案 2 :(得分:0)
您正在同步方法,因此锁定对象是每种情况下的对象(ca和cb)。
当线程调用cb.fooB(ca)
时,它会抓取锁定对象cb。
然后主线程调用ca.fooA(cb)
,因此抓住锁定对象ca。
但是,fooA
方法在主线程中调用cb.lastB()
,并且此方法也是同步的,因此主线程尝试获取锁定cb,只发现另一个线程具有已经锁定,所以必须等待。
与此同时,另一个线程调用了cb.fooB(ca)
,后者又调用ca.lastA()
,所以试图抓住ca上的锁,只发现主线程已经有锁,所以它也必须等待。
结果:每个线程都有一个锁,另一个需要继续,所以他们互相等待。死锁。