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

Java多线程同步死锁问题:计数器wait/notify实现故障求助

问题分析与解决

你的代码出现死锁的核心原因有两个:

  1. 用if而非while检查等待条件:线程被notify()唤醒后不会重新判断当前条件是否满足,直接继续执行,导致不符合执行条件时仍操作变量,最终引发线程互相等待。
  2. 唤醒逻辑的随机性:notify()只会随机唤醒一个等待线程,如果唤醒的是同类线程(比如增量线程唤醒另一个增量线程),该线程醒来后仍不满足执行条件,会再次进入等待,最终所有线程都陷入等待。

关键修改点

  • 将等待条件的if替换为while,确保线程被唤醒后重新检查条件,只有满足条件才继续执行。
  • 调整方法内的逻辑顺序:先判断是否允许执行操作,再进行增减,避免先修改变量后判断导致的逻辑混乱。
  • 用notifyAll()替代notify(),确保所有等待线程都能收到唤醒信号,避免同类线程被唤醒后再次等待的情况。

修改后的完整代码

class Mythread implements Runnable {
    Counter q;
    int i = 1;

    Mythread(Counter q) {
        this.q = q;
        new Thread(this).start();
    }

    @Override
    public void run() {
        while (i <= 10) {
            q.increment();
            i++;
        }
    }
}

class Mythread2 implements Runnable {
    Counter q;
    int i = 1;

    Mythread2(Counter q) {
        this.q = q;
        new Thread(this).start();
    }

    @Override
    public void run() {
        while (i <= 10) {
            q.decrement();
            i++;
        }
    }
}

class Counter {
    private int count = 0; // 调整初始值为0,避免decrement线程一开始就等待
    private static final int MAX_COUNT = 3; // 用常量定义阈值,更易维护

    synchronized void increment() {
        try {
            // 当count达到最大值时,等待直到被减到0
            while (count >= MAX_COUNT) {
                System.out.println("已达最大值" + MAX_COUNT + ",等待递减至0");
                wait();
            }
            System.out.println("递增后:" + ++count);
            notifyAll(); // 唤醒所有等待线程
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
        }
    }

    synchronized void decrement() {
        try {
            // 当count小于0时,等待直到有递增操作
            while (count < 0) {
                System.out.println("count已小于0,等待递增");
                wait();
            }
            System.out.println("递减后:" + count--);
            notifyAll(); // 唤醒所有等待线程
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

class q3 {
    public static void main(String[] args) {
        Counter q = new Counter();
        new Mythread(q);
        new Mythread2(q);
    }
}

代码说明

  1. while循环检查条件:每次线程被唤醒后,都会重新判断当前count是否符合执行条件,确保只有满足条件时才进行增减操作。
  2. 调整初始值:将count初始值设为0,避免decrement线程一开始就进入等待状态,保证程序能正常启动。
  3. 使用notifyAll():确保所有等待的线程都能收到唤醒信号,避免出现同类线程被唤醒后再次等待的情况,彻底解决死锁隐患。
  4. 恢复中断状态:捕获InterruptedException后恢复线程的中断状态,符合Java线程中断的最佳实践。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 11:35:40