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

Java多线程打印静态变量异常输出11的原因排查及指定输出实现

异常产生原因

核心问题源自wait()方法的执行特性和代码的条件校验逻辑缺陷:

  • wait()会让当前线程释放锁陷入阻塞,被notify()唤醒后,线程会直接从wait()调用的位置继续向下执行,不会重新校验外层的循环边界条件i <= 10。
  • 代码中等待条件使用if判断,仅会在校验进入等待前判断一次条件,唤醒后不会二次校验等待条件是否仍然成立,也不会校验i是否已经超出打印边界。

具体执行流程对应你给出的输出:

  1. 当i=10时,Thread-0(负责打印1-4、8-10)进入同步块,i<=10判断成立,且i=10不属于5-7的等待区间,直接打印10 Thread-0,执行i++后i变为11,调用notify()唤醒处于阻塞状态的Thread-1。
  2. Thread-1此前因i=8命中等待条件陷入阻塞,被唤醒后直接向下执行打印逻辑,此时i=11就被异常输出,之后才会回到外层while(i<=10)判断,发现条件不成立退出循环。
修复方案

按照Java多线程wait()的最佳实践做两处修改即可:

  1. 所有等待条件从if判断改为while循环判断,确保线程被唤醒后会重新校验等待条件是否仍然成立,同时覆盖边界校验。
  2. 打印逻辑前增加边界判断,避免i超出10后仍然执行打印。

修改后的核心代码如下:

void print2()
{
    synchronized (this) {
        while (i <= 10) {
            // 等待条件改为while循环,唤醒后重新校验
            while (i <=10 && ((i > 0 && i < 5) || (i > 7 && i < 11))) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 边界校验,超出范围直接退出
            if(i > 10) break;
            System.out.println(i + " " + Thread.currentThread().getName());
            i++;
            notify();
        }
    }
}
void print1()
{
    synchronized (this) {
        while (i <= 10)
        {
            // 等待条件改为while循环
            while (i <=10 && i > 4 && i < 8) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 边界校验,超出范围直接退出
            if(i > 10) break;
            System.out.println(i + " "+Thread.currentThread().getName());
            i++;
            notify();
        }
    }
}

内容的提问来源于stack exchange,提问作者Akash Kumar Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 10:51:03