You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何未发生死锁?先调用a.foo(b)再启动线程无死锁的原因

为什么先调用a.foo(b)再启动线程不会死锁?

首先咱们先把代码补全,还原经典的死锁场景(你的代码里A类的last()没写完,B类也缺失,我补全成常见的死锁示例):

class A { 
    synchronized void foo(B b) { 
        String name = Thread.currentThread().getName(); 
        System.out.println(name + " entered A.foo"); 
        try { 
            Thread.sleep(2000); 
        } catch (Exception e) { 
            System.out.println("A Interrupted"); 
        } 
        System.out.println(name + " trying to call B.last()"); 
        b.last(); 
    } 
    synchronized void last() { 
        System.out.println("Inside A.last"); 
    }
}

class B {
    synchronized void bar(A a) {
        String name = Thread.currentThread().getName();
        System.out.println(name + " entered B.bar");
        try {
            Thread.sleep(2000);
        } catch (Exception e) {
            System.out.println("B Interrupted");
        }
        System.out.println(name + " trying to call A.last()");
        a.last();
    }
    synchronized void last() {
        System.out.println("Inside B.last");
    }
}

class Deadlock {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        Thread t = new Thread(() -> {
            b.bar(a); // 线程t要执行的逻辑:拿B的锁,再要A的锁
        });

        // 重点:先调用a.foo(b),再启动线程t
        a.foo(b);
        t.start();
    }
}

先搞懂死锁的核心:

死锁发生的前提是两个线程各自持有一个对方需要的锁,同时都在等待对方释放锁,四个条件缺一不可:互斥、持有并等待、不可剥夺、循环等待。

现在分析你说的执行流程:

当你先调用a.foo(b),再执行t.start()时,整个过程是这样的:

  1. 主线程先执行a.foo(b):
    • 因为foo()是synchronized方法,主线程会立刻拿到A对象的锁(同步方法的锁是当前实例,也就是a)。
    • 然后主线程进入sleep(2000),这时候它依然持有A的锁,不会释放。
    • 2秒后sleep结束,主线程执行b.last():last()是B类的同步方法,所以主线程会拿到B对象的锁,执行完B.last()后释放B的锁。
    • 最后a.foo(b)方法执行完毕,主线程释放A的锁。
  2. 主线程才会执行t.start():
    • 线程t启动后,执行b.bar(a):拿到B对象的锁,sleep2秒。
    • 2秒后sleep结束,线程t执行a.last():这时候A的锁已经被主线程释放了,所以线程t能顺利拿到A的锁,执行完A.last()后释放A的锁,最后b.bar(a)执行完毕,释放B的锁。

为什么不会死锁?

因为两个线程的锁请求是串行的:主线程先把A锁和B锁的操作全部完成,释放所有锁之后,线程t才开始请求锁。根本不会出现“两个线程各持一个锁、互相等待”的情况,自然就不会触发死锁。

对比一下死锁的场景:

如果把顺序反过来,先t.start()再调用a.foo(b),那才会触发死锁:

  • 线程t启动后拿到B的锁,sleep时主线程调用a.foo(b)拿到A的锁。
  • 两者sleep结束后,线程t要拿A的锁(被主线程拿着),主线程要拿B的锁(被线程t拿着),互相等待,死锁就发生了。

内容的提问来源于stack exchange,提问作者Rajan saha Raju

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:53:15