使用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(); } } }
关键细节解释
- synchronized方法:保证同一时刻只有一个线程能进入
printNumber方法,避免状态变量被多线程同时修改导致混乱。 - while循环检查状态:必须用while而不是if!因为wait()可能会遇到虚假唤醒(线程在没有被notify的情况下醒来),每次唤醒后必须重新确认当前状态是否匹配自己的编号。
- notifyAll()而非notify():notify()只会随机唤醒一个等待的线程,如果唤醒的不是下一个该执行的线程,程序会卡住。notifyAll()唤醒所有等待的线程,让它们都去检查状态,确保下一个线程能及时执行。
- 循环状态更新:
currentThreadId = currentThreadId % totalThreads + 1完美处理了线程循环的情况,比如3个线程时,第3个线程执行完后,状态会回到1,实现重复循环打印。
运行这段代码,你就能得到你想要的输出:111111111 222222222 333333333 111111111 222222222 333333333
内容的提问来源于stack exchange,提问作者Roman Vinokurov
相关产品推荐
相关产品推荐

