Java双线程打印自然数遇无限等待:仅输出1需调试
为啥程序只打印1就卡住了?
- 锁对象不共享:
odd和even是两个独立的Runnable对象,各自的synchronized (this)锁的是自己,导致两个线程的wait()和notify()根本不在同一个“通知频道”上。奇数线程打印完1后调用notify(),但偶数线程在另一个锁上等着,根本收不到通知,就一直卡着;奇数线程也因为后续counter变成2,进入counter%2==0的循环,调用wait(),同样没人唤醒它,俩线程都无限等待。 - 循环条件漏了最后一个数:原代码用
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
相关产品推荐
相关产品推荐

