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

多同步方法线程顺序控制问题:为何无法按A→B→C顺序循环打印三次?

解决你的Java多线程顺序打印问题

嘿,我来帮你梳理下代码里的问题,以及怎么修复它~

你的核心问题是没有一个明确的状态标记来管控线程的执行顺序,再加上notify()是随机唤醒等待线程的,这就导致了输出顺序乱掉。咱们一步步来看:

你遗漏的关键逻辑

  • 缺少一个共享的状态变量,用来标记当前该哪个线程发言
  • 每个线程拿到锁后,不能直接就打印,得先确认是不是轮到自己了
  • 用notifyAll()替代notify()会更可靠,这样能唤醒所有等待的线程,让它们自己判断是否该执行

修正后的代码

public class Chat {
    // 用枚举定义发言顺序,清晰直观
    enum Speaker { A, B, C }
    // 初始设置为A先发言
    private Speaker currentSpeaker = Speaker.A;

    synchronized void chatA(){
        for(int i = 0; i<3; i++) {
            // 循环等待,直到轮到自己
            while(currentSpeaker != Speaker.A) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("A");
            // 切换到下一个发言者B
            currentSpeaker = Speaker.B;
            // 唤醒所有等待线程,让它们检查状态
            notifyAll();
        }
    }

    synchronized void chatB(){
        for(int i=0; i<3; i++) {
            while(currentSpeaker != Speaker.B) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("B");
            currentSpeaker = Speaker.C;
            notifyAll();
        }
    }

    synchronized void chatC(){
        for(int i=0; i<3; i++) {
            while(currentSpeaker != Speaker.C) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("C");
            // 切换回A,完成一轮循环
            currentSpeaker = Speaker.A;
            notifyAll();
        }
    }

    public static void main(String[] args){
        Chat chat = new Chat();
        Thread t1 = new Thread(chat::chatA);
        Thread t2 = new Thread(chat::chatB);
        Thread t3 = new Thread(chat::chatC);

        t1.start();
        t2.start();
        t3.start();
    }
}

为什么这样改?

  1. 状态变量currentSpeaker:相当于一个“发言令牌”,只有拿到令牌的线程才能执行打印操作
  2. while循环检查令牌:用while而不是if是为了防止虚假唤醒——线程可能会在没被正确通知的情况下醒来,这时候得再确认一遍令牌是不是自己的
  3. notifyAll()唤醒所有线程:这样所有等待的线程都会醒来检查令牌,只有持有正确令牌的线程会继续执行,保证了顺序不会乱
  4. 切换令牌:每个线程打印完后,把令牌传给下一个线程,形成A→B→C→A的循环,完美实现各打印3次的需求

现在运行这段代码,就能得到你想要的A、B、C依次打印3次的结果啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 15:52:46