为什么在这种情况下不会发生死锁

why doesn't deadlock occur in this situation

public class TestClass {

public synchronized void func1() throws InterruptedException {
        System.out.println("func1");
        long a = System.nanoTime();
        func2();

}

public synchronized void func2() throws InterruptedException {
        System.out.println("func2");
        long a = System.nanoTime();
        while (System.nanoTime() - a < 10000000) {
            ;
        }

        func1();

} }

public class ThreadSample extends Thread {

TestClass testClass;
public ThreadSample(TestClass testClass)
{
    this.testClass = testClass;
}
@Override
public void run() {
    try {
        testClass.func2();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}}

public class Main {
public static void main(String[] args) throws InterruptedException {

    TestClass testClass = new TestClass();
    ThreadSample threadSample  = new ThreadSample(testClass);
    threadSample.start();
    testClass.func1();
}}

请看上面的代码。为什么这里不发生死锁?因为Main线程在func1里面,想去func2但是去不了,因为func2被ThreadSample锁住了。而ThreadSample也不能去func1。所以我们应该面临僵局,但我们没有。

为什么?

只有在有多个锁时才会出现死锁

在这种情况下,func2func1 在同一个 lock 监视器(TestClass 的实例)上同步。一旦一个线程获得了这个锁,其他线程将被阻塞,直到它释放锁。


假设main thread已经进入了func1,也就是说它已经获得了锁,其他线程不能同时调用func2时间。因为 fun1fun2 使用的是同一个锁!而在 fun1 中,这个线程可以调用 fun2 因为 synchronized 块是可重入的。

您可以用 sleep 替换 func2() 方法,如下所示,以锁定 testClass 对象:

public synchronized void func2() throws InterruptedException {
    System.out.println("func2");
    long a = System.nanoTime();
    Thread.sleep(1000000000000L);
    //func1();
}

现在,threadSample 线程首先获得锁(启动后)在 func2 中等待(持有 testClass 对象上的锁)因此 main 线程可以'甚至进入 func1() 等待锁定同一对象。