ZeroEvenOdd同步问题:输出顺序正确但程序无法终止
看起来你的代码已经实现了正确的输出顺序,但程序一直无法终止,这是因为有线程卡在了wait()调用中无法醒来,导致主线程的join()一直等待这些线程结束。我来帮你分析问题出在哪,以及怎么修复。
问题根源分析
我们先看最后一轮循环结束后的状态:
当zeroCounter达到11(超过loop=10),Zero线程会退出循环,正常终止。但此时Odd或Even线程可能还卡在wait()里:
比如,当Even线程处理完最后一个偶数10后,oddEvenCounter变成11,signal被设为true,然后调用notifyAll()。此时如果Odd线程之前在等待,它会被唤醒,但它的等待条件是:
while( (signal) || (oddEvenCounter % 2 == 0)) { wait(); }
此时signal是true,所以这个while条件仍然成立,Odd线程会再次进入wait()状态。而此时Zero线程和Even线程都已经终止,没有其他线程会再调用notifyAll(),Odd线程就会一直卡在wait里,导致整个程序无法结束。
同样的情况也可能发生在Even线程身上,如果最后一次是Odd线程处理完9,Zero打印10后,Even线程被唤醒,但后续如果状态不对也可能卡住。
核心问题是:当循环任务已经完成(oddEvenCounter超过loop),线程仍然可能进入wait循环,没有机会退出外层的while循环。
修复方案
我们需要在每个wait的循环条件中,加入“任务是否已完成”的判断,确保当任务结束时,线程不会再进入wait,而是直接退出循环。修改后的SynchronizedResource类如下:
public class SynchronizedResource { private final int loop; private int zeroCounter; private int oddEvenCounter; private boolean signal = true; public SynchronizedResource(int loop) { this.loop = loop; this.zeroCounter = 1; this.oddEvenCounter = 1; } public synchronized void zeroPrinting() { try { while (zeroCounter <= loop) { // 新增任务完成判断:如果zeroCounter超过loop,不再等待 while (zeroCounter <= loop && !signal) { wait(); } // 再次判断,避免被唤醒后任务已完成 if (zeroCounter > loop) { break; } System.out.println("Printing Zero 0 with iteration number :- " + zeroCounter + " " + Thread.currentThread().getName()); zeroCounter = zeroCounter + 1; signal = false; notifyAll(); } } catch (InterruptedException exception) { System.out.println(exception.getMessage()); // 中断后重置中断状态 Thread.currentThread().interrupt(); } } public synchronized void evenPrinting() { try { while (oddEvenCounter <= loop) { // 新增任务完成判断:如果oddEvenCounter超过loop,不再等待 while (oddEvenCounter <= loop && (signal || (oddEvenCounter % 2 != 0))) { wait(); } // 再次判断,避免被唤醒后任务已完成 if (oddEvenCounter > loop) { break; } System.out.println("Printing Even number " + oddEvenCounter + " " + Thread.currentThread().getName()); oddEvenCounter++; signal = true; notifyAll(); } } catch (InterruptedException exception) { System.out.println(exception.getMessage()); Thread.currentThread().interrupt(); } } public synchronized void oddPrinting() { try { while (oddEvenCounter <= loop) { // 新增任务完成判断:如果oddEvenCounter超过loop,不再等待 while (oddEvenCounter <= loop && (signal || (oddEvenCounter % 2 == 0))) { wait(); } // 再次判断,避免被唤醒后任务已完成 if (oddEvenCounter > loop) { break; } System.out.println("Printing Odd number " + oddEvenCounter + " " + Thread.currentThread().getName()); oddEvenCounter++; signal = true; notifyAll(); } } catch (InterruptedException exception) { System.out.println(exception.getMessage()); Thread.currentThread().interrupt(); } } }
关键修改点
- 在wait循环中加入任务完成判断:比如在
oddPrinting的wait循环里,我们加上oddEvenCounter <= loop作为前置条件,确保当任务已经完成时,不会再进入wait。 - 唤醒后再次检查任务状态:即使线程被唤醒,也要先判断任务是否已经完成,如果完成就直接退出外层循环,避免执行后续打印逻辑。
- 处理中断异常:在catch块中重置线程的中断状态,避免线程状态异常。
这样修改后,所有线程都会在任务完成后正常退出,主线程的join()会顺利执行,程序最终会打印Program executed successfully........并终止。
内容来源于stack exchange

