Java发生死锁的根本原因是:在申请锁时发生了交叉闭环申请。即线程在获得了锁A并且没有释放的情况下去申请锁B,这时,另一个线程已经获得了锁B,在释放锁B之前又要先获得锁A,因此闭环发生,陷入死锁循环。 这是我在搜索死锁时,在川森的博客中看到的,他的博客中关于死锁写的已经很详细了,这里我就不多赘述了。
但是为什么我还要写这篇博客呢,因为在川森的博客中有一个例子特别有意思。这里附上源码
public class TestClass {
public synchronized void method(TestClass clazz) {
System.out.println("TestClass method in");
clazz.method2();
System.out.println("TestClass method out");
}
public synchronized void method2() {
System.out.println("TestClass method2");
}
}
public class TestLock extends Thread {
private TestClass class1;
private TestClass class2;
public TestLock(TestClass class1, TestClass class2) {
this.class1 = class1;
this.class2 = class2;
}
@Override
public void run() {
class1.method(class2);
}
}
public class Client {
public static void main(String[] ars) {
TestClass classA = new TestClass();
TestClass classB = new TestClass();
new TestLock(classA, classB).start();
new TestLock(classB, classA).start();
}
}
他的运行结果是:
但是在看到这个例子的时候,我产生了很多大怀疑,并且也不只是我自己,在博文中为数不多的评论中也表达这不是死锁的怀疑:
然后我有查询了相关资料,才发现自己陷入一个误区。这个误区就是我以为synchronized取得的是方法锁…实际上
synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为“互斥区”或“临界区”。关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁。
在静态方法上添加关键字synchronized,表示锁定.class类,属于类级别的锁。
那么,在认清synchronized取得的锁都是对象锁后,在川森的例子中我们就能够的清晰的认识到,当调用第一个线程时,线程一取得了classA的锁,当调用第二个线程时,线程二取得了classB的锁,所以,在线程一调用classB的method2方法时,就出现了死锁现象。