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

ZeroEvenOdd同步问题:输出顺序正确但程序无法终止

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 07:48:10