双线程交替打印数字:wait()与notify()实现方式正确性问询
关于wait()/notify()实现交替打印数字的正确性分析
嘿,我来帮你梳理这个问题~首先从你给出的主类代码来看,两个线程共享同一个MyThread1实例是正确的思路——这样才能保证锁对象和共享计数变量是同一个实例,为线程间同步打好基础。不过你贴的线程类代码不完整,我结合常见的实现误区和正确规范来给你分析:
先明确wait()/notify()的核心规则(必须遵守,否则实现肯定错)
- wait()/notify()/notifyAll()必须在同步块/同步方法内调用:调用这些方法的线程必须持有对应锁对象的monitor,不然会直接抛出
IllegalMonitorStateException。 - 必须用循环检查等待条件:绝对不能用
if判断!因为线程可能遭遇「虚假唤醒」(spurious wakeup)——也就是没有被notify()唤醒也会从wait()返回,循环能确保唤醒后重新校验条件是否满足。 - 共享变量要保证可见性:要么用
volatile修饰,要么只在同步块内访问,避免线程读取到过期的变量值。 - 必须处理InterruptedException:wait()会抛出这个异常,捕获后要合理处理(比如中断当前线程并退出),否则编译不通过。
常见的错误实现(如果你的代码有这些问题,就是不正确的)
- 在同步块外调用wait/notify:这是新手最容易犯的错,直接触发运行时异常。
- 用if判断执行条件:比如线程被唤醒后,可能计数已经被另一个线程修改了,if判断会导致错误执行。
- 滥用notify()而非notifyAll():notify()只会随机唤醒一个等待线程,如果有多个线程等待,可能唤醒的不是目标线程,导致某个线程永久阻塞。
- 忽略共享变量的可见性:比如计数变量没加
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
相关产品推荐
相关产品推荐

