
本文详解 java 中多线程协作打印奇偶数时因锁对象不一致导致的无限等待问题,提供正确同步方案、可运行代码及关键注意事项。
本文详解 java 中多线程协作打印奇偶数时因锁对象不一致导致的无限等待问题,提供正确同步方案、可运行代码及关键注意事项。
在 Java 多线程编程中,使用 wait()/notify() 实现线程间协作是一个经典场景,但极易因同步对象不统一而陷入死锁或无限等待。原代码试图让两个线程(分别负责打印奇数和偶数)交替输出前 N 个自然数,却只输出 1 后停滞——根本原因在于:odd 和 even 两个 Runnable 实例各自以 this 为锁对象,彼此无法感知对方的 notify() 调用,导致 wait() 永不被唤醒。
✅ 正确做法:共享同一锁对象
必须确保所有参与协作的线程在同一个对象上同步、等待和通知。推荐使用 static final Object lock = new Object(); 作为全局协调锁:
import java.util.Scanner;
public class OddEven {
static final Object lock = new Object(); // ✅ 共享锁对象
static int totalNos;
static int counter = 1;
static Runnable odd = () -> {
synchronized (lock) {
while (counter {
synchronized (lock) {
while (counter <h3>⚠️ 关键注意事项</h3>
- wait()/notify() 必须在 synchronized 块内调用,且锁对象必须与 synchronized 的对象一致;
- 使用 while 而非 if 判断条件(防止虚假唤醒);
- counter
- 主线程应调用 join() 确保输出完整后再退出;
- InterruptedException 应恢复中断状态(Thread.currentThread().interrupt()),而非仅打印堆栈;
- 避免在 Runnable 中直接使用 this 作为锁——它指向匿名内部类实例,每个 Runnable 实例互不相同。
✅ 运行示例
输入 6,输出:
1 2 3 4 5 6
该方案通过统一锁对象、严谨的条件检查和线程协作机制,彻底解决无限等待问题,是 Java 并发编程中 wait/notify 模式的基础实践范例。










