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

Java双线程打印自然数遇无限等待:仅输出1需调试

为啥程序只打印1就卡住了?

  1. 锁对象不共享:odd和even是两个独立的Runnable对象,各自的synchronized (this)锁的是自己,导致两个线程的wait()和notify()根本不在同一个“通知频道”上。奇数线程打印完1后调用notify(),但偶数线程在另一个锁上等着,根本收不到通知,就一直卡着;奇数线程也因为后续counter变成2,进入counter%2==0的循环,调用wait(),同样没人唤醒它,俩线程都无限等待。
  2. 循环条件漏了最后一个数:原代码用while(counter < totalNos),比如输入N=5,counter到5的时候不满足<5,直接退出循环,数字5就打不出来;输入N=4的话,数字4也打不出来。

修复后的代码

import java.util.Scanner;

public class OddEven {
    static int totalNos;
    static int counter = 1;
    // 搞个共享的锁对象,让俩线程用同一个通知频道
    static final Object lock = new Object();

    static Runnable odd = new Runnable() {
        @Override
        public void run() {
            synchronized (lock) {
                // 改成<=,保证最后一个数能被处理
                while (counter <= totalNos) {
                    // 当前是偶数的话,等着偶数线程处理
                    while (counter % 2 == 0) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            // 遇到中断直接退出,避免无效等待
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }
                    // 防止最后一次唤醒后打印超出范围的数
                    if (counter > totalNos) {
                        lock.notify();
                        break;
                    }
                    System.out.print(counter + " ");
                    counter++;
                    // 通知偶数线程可以干活了
                    lock.notify();
                }
            }
        }
    };

    static Runnable even = new Runnable() {
        @Override
        public void run() {
            synchronized (lock) {
                while (counter <= totalNos) {
                    // 当前是奇数的话,等着奇数线程处理
                    while (counter % 2 == 1) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }
                    if (counter > totalNos) {
                        lock.notify();
                        break;
                    }
                    System.out.print(counter + " ");
                    counter++;
                    // 通知奇数线程可以干活了
                    lock.notify();
                }
            }
        }
    };

    public static void main(String[] args) {
        System.out.println("Enter the total no's");
        Scanner scObj = new Scanner(System.in);
        totalNos = scObj.nextInt();
        scObj.close();
        Thread oddT1 = new Thread(odd);
        Thread evenT1 = new Thread(even);
        oddT1.start();
        evenT1.start();
    }
}

核心修复点

  • 共用锁对象:用static final Object lock作为两个线程的同步锁,让它们的等待和通知都在同一个“频道”上,能互相唤醒。
  • 修正循环条件:把counter < totalNos改成counter <= totalNos,确保最后一个自然数不会被漏掉。
  • 加边界检查:打印前先判断counter是否超出范围,避免线程被唤醒后打印不该打的数。
  • 优化中断处理:捕获中断后直接终止线程,避免无效等待。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 03:49:57