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

双线程交替打印数字:wait()与notify()实现方式正确性问询

关于wait()/notify()实现交替打印数字的正确性分析

嘿,我来帮你梳理这个问题~首先从你给出的主类代码来看,两个线程共享同一个MyThread1实例是正确的思路——这样才能保证锁对象和共享计数变量是同一个实例,为线程间同步打好基础。不过你贴的线程类代码不完整,我结合常见的实现误区和正确规范来给你分析:

先明确wait()/notify()的核心规则(必须遵守,否则实现肯定错)

  • wait()/notify()/notifyAll()必须在同步块/同步方法内调用:调用这些方法的线程必须持有对应锁对象的monitor,不然会直接抛出IllegalMonitorStateException。
  • 必须用循环检查等待条件:绝对不能用if判断!因为线程可能遭遇「虚假唤醒」(spurious wakeup)——也就是没有被notify()唤醒也会从wait()返回,循环能确保唤醒后重新校验条件是否满足。
  • 共享变量要保证可见性:要么用volatile修饰,要么只在同步块内访问,避免线程读取到过期的变量值。
  • 必须处理InterruptedException:wait()会抛出这个异常,捕获后要合理处理(比如中断当前线程并退出),否则编译不通过。

常见的错误实现(如果你的代码有这些问题,就是不正确的)

  1. 在同步块外调用wait/notify:这是新手最容易犯的错,直接触发运行时异常。
  2. 用if判断执行条件:比如线程被唤醒后,可能计数已经被另一个线程修改了,if判断会导致错误执行。
  3. 滥用notify()而非notifyAll():notify()只会随机唤醒一个等待线程,如果有多个线程等待,可能唤醒的不是目标线程,导致某个线程永久阻塞。
  4. 忽略共享变量的可见性:比如计数变量没加volatile,也不在同步块内访问,会导致线程看不到最新值,陷入死循环或打印重复数字。

正确的实现示例(供你参考对照)

假设我们要实现t1打印奇数、t2打印偶数,交替输出1到10,正确的线程类应该是这样的:

public class MyThread1 implements Runnable {
    private int count = 1;
    private final Object lock = new Object(); // 共享锁对象

    @Override
    public void run() {
        while (count <= 10) {
            synchronized (lock) {
                // 循环检查当前线程是否可以执行
                while ((Thread.currentThread().getName().equals("t1") && count % 2 == 0)
                        || (Thread.currentThread().getName().equals("t2") && count % 2 != 0)) {
                    try {
                        lock.wait(); // 不满足条件则等待,释放锁
                    } catch (InterruptedException e) {
                        // 捕获中断异常,中断当前线程并退出
                        Thread.currentThread().interrupt();
                        return;
                    }
                }

                // 执行打印逻辑
                System.out.println(Thread.currentThread().getName() + ": " + count);
                count++;
                // 唤醒所有等待的线程,确保另一个线程能继续执行
                lock.notifyAll();
            }
        }
    }
}

这个实现正确的原因

  • 同步块包裹所有锁相关操作:wait()、notifyAll()和对count的读写都在synchronized(lock)内,保证线程安全和锁的正确持有。
  • 循环校验条件:每次被唤醒后都重新判断是否符合执行条件,彻底避免虚假唤醒的问题。
  • notifyAll()唤醒所有等待线程:确保另一个等待的线程能拿到锁并继续执行,不会出现线程永久等待的情况。
  • 合理处理中断异常:保证线程在被中断时能优雅退出,避免资源泄漏。

如果你的线程类没有遵循这些规则,那你的实现大概率是不正确的。比如如果你的代码里wait()不在同步块中,或者用if判断条件,都会导致程序报错或者打印顺序混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:41:37