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

Java多线程wait/notifyAll逻辑触发死锁的缺陷排查

核心缺陷说明

你的代码有3个关键逻辑错误,是导致死锁、逻辑不符合预期的根本原因:

  • 第一处致命错误:错误调用run()而非start()启动线程
    Thread类的run()是普通方法,直接调用不会创建新的执行线程,只会在当前执行ma()的主线程中同步执行run()内的全部逻辑。代码实际执行流程为:
    1. 主线程调用thread.run(),直接进入第一个线程的执行逻辑
    2. 执行完b.mb1()后,主线程获取object的内置锁,调用object.wait()进入阻塞状态并释放锁
    3. 此时主线程已经卡在等待状态,后续的thread1.run()调用、notifyAll()唤醒逻辑永远没有机会执行,程序直接死锁。
  • 第二处错误:存在竞态条件,唤醒时机无保障
    就算把run()改成start()真正启动子线程,现有逻辑也无法保证「两个子线程都进入wait状态后主线程才执行notifyAll()」。子线程启动后的调度时机完全由操作系统决定,完全可能出现主线程先拿到锁执行完notifyAll(),两个子线程之后才进入wait状态的情况,此时子线程会永远等不到唤醒信号,再次死锁。
  • 第三处错误:wait()调用不符合Java规范,未绑定条件判断
    Java内置锁的wait()方法存在虚假唤醒问题:线程可能在没有被notify()/notifyAll()唤醒、也没有被中断的情况下从wait状态返回。如果不把wait()放在循环中、每次唤醒后都检查等待条件是否真的满足,会出现线程提前执行后续逻辑的问题。
修正方案

按照你原本的设计逻辑,需要引入共享计数变量标记已经执行完mb1()的线程数,作为wait/notify的判断条件,同时修正线程启动方式。参考实现如下:

public class AImpl{
    public static final Object lock = new Object();
    // 记录已经执行完mb1的线程数
    public static int mb1FinishCount = 0;

    public static void main(String[] args) throws InterruptedException {
        BImpl b = new BImpl();
        AImpl.ma(b);
    }

    public static void ma(B b) throws InterruptedException {
        Thread thread = new Thread() {
            @Override
            public void run() {
                b.mb1();
                synchronized(lock){
                    mb1FinishCount++;
                    // 只要还有线程没执行完mb1,就等待
                    while (mb1FinishCount < 2) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            return;
                        }
                    }
                    // 第二个执行完mb1的线程负责唤醒所有等待线程
                    lock.notifyAll();
                }
                b.mb2();
                System.out.println("Thread finished");
            }
        };

        Thread thread1 = new Thread() {
            @Override
            public void run() {
                b.mb1();
                synchronized(lock){
                    mb1FinishCount++;
                    while (mb1FinishCount < 2) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            return;
                        }
                    }
                    lock.notifyAll();
                }
                b.mb2();
                System.out.println("Thread finished");
            }
        };
        // 正确启动两个独立子线程
        thread.start();
        thread1.start();

        // 主线程等待两个线程都执行完mb1再结束
        synchronized (lock) {
            while (mb1FinishCount < 2) {
                lock.wait();
            }
        }

        System.out.println("Program finished.");
    }
}

注:如果不需要手动练习wait/notify机制,实际生产代码中直接用CountDownLatch等JUC工具类实现线程协作会更简洁,也不容易出错。

内容的提问来源于stack exchange,提问作者BlueRyse

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 03:51:19