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

使用wait/notify实现线程顺序执行的技术问题求助

用wait/notify实现线程顺序打印的解决方案

嘿,我明白你遇到的问题了——用wait/notify实现线程顺序执行确实需要抓准核心逻辑,和你之前用interrupt的思路不太一样。我来给你拆解一下怎么搞,代码和原理都给你讲清楚。

核心思路

要让线程按顺序执行,我们需要一个共享的控制中心:

  • 一个锁对象(用synchronized保证线程安全)
  • 一个状态变量标记当前该哪个线程执行
  • 每个线程只在状态匹配自己编号时才打印,否则进入等待;打印完成后更新状态并唤醒所有等待的线程,让下一个线程继续。

完整代码实现

首先定义共享的控制类,负责管理线程执行顺序:

class ThreadOrderController {
    private int currentThreadId; // 当前可执行的线程编号
    private final int totalThreads; // 总线程数X
    private final int charCountPerPrint; // 每次打印的字符数Y
    private final int loopTimes; // 每个线程循环打印的次数Z

    public ThreadOrderController(int totalThreads, int charCountPerPrint, int loopTimes) {
        this.totalThreads = totalThreads;
        this.charCountPerPrint = charCountPerPrint;
        this.loopTimes = loopTimes;
        this.currentThreadId = 1; // 从第1个线程开始执行
    }

    // 线程调用此方法完成打印逻辑
    public synchronized void printNumber(int threadId) throws InterruptedException {
        for (int i = 0; i < loopTimes; i++) {
            // 循环等待:直到当前轮到自己执行(防止虚假唤醒)
            while (currentThreadId != threadId) {
                wait();
            }

            // 打印Y个当前线程对应的数字
            System.out.print(String.valueOf(threadId).repeat(charCountPerPrint) + " ");

            // 更新下一个要执行的线程编号(循环回到1)
            currentThreadId = currentThreadId % totalThreads + 1;

            // 唤醒所有等待的线程,让它们检查是否轮到自己
            notifyAll();
        }
    }
}

然后是自定义线程类,持有控制中心和自己的编号:

class NumberPrintThread extends Thread {
    private final ThreadOrderController controller;
    private final int threadId;

    public NumberPrintThread(ThreadOrderController controller, int threadId) {
        this.controller = controller;
        this.threadId = threadId;
    }

    @Override
    public void run() {
        try {
            controller.printNumber(threadId);
        } catch (InterruptedException e) {
            // 处理中断,恢复线程中断状态
            Thread.currentThread().interrupt();
        }
    }
}

最后是测试主类,启动线程:

public class Main {
    public static void main(String[] args) {
        int X = 3; // 总线程数
        int Y = 9; // 每次打印的字符数
        int Z = 2; // 每个线程循环打印次数

        ThreadOrderController controller = new ThreadOrderController(X, Y, Z);

        // 创建并启动X个线程
        for (int i = 1; i <= X; i++) {
            new NumberPrintThread(controller, i).start();
        }
    }
}

关键细节解释

  1. synchronized方法:保证同一时刻只有一个线程能进入printNumber方法,避免状态变量被多线程同时修改导致混乱。
  2. while循环检查状态:必须用while而不是if!因为wait()可能会遇到虚假唤醒(线程在没有被notify的情况下醒来),每次唤醒后必须重新确认当前状态是否匹配自己的编号。
  3. notifyAll()而非notify():notify()只会随机唤醒一个等待的线程,如果唤醒的不是下一个该执行的线程,程序会卡住。notifyAll()唤醒所有等待的线程,让它们都去检查状态,确保下一个线程能及时执行。
  4. 循环状态更新:currentThreadId = currentThreadId % totalThreads + 1 完美处理了线程循环的情况,比如3个线程时,第3个线程执行完后,状态会回到1,实现重复循环打印。

运行这段代码,你就能得到你想要的输出:111111111 222222222 333333333 111111111 222222222 333333333

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:22:56