Java中实现线程交替打印ABC的关键是精准控制执行权交接,常用synchronized+wait/notifyAll、ReentrantLock+Condition、AtomicInteger自旋或Semaphore四种方式,核心均为状态判断、条件等待与精确唤醒。

Java 中实现线程交替打印 ABC(比如三个线程分别打印 A、B、C,按 A→B→C→A→B→C… 顺序循环)的关键在于:**精准控制执行权的交接,确保每次只有一个线程能打印,且必须按固定顺序唤醒下一个线程**。常用手段是结合 synchronized + wait()/notifyAll(),或使用 ReentrantLock + Condition,核心都是“状态判断 + 条件等待 + 精确唤醒”。
用 synchronized + wait/notifyAll 控制顺序
定义一个共享状态变量(如 current,0 表示轮到 A,1 表示 B,2 表示 C),每个线程在进入临界区后先检查是否轮到自己;不是就 wait() 挂起;是则打印、更新状态、调用 notifyAll() 唤醒所有等待线程重新竞争。
- 注意必须用
while而非if判断条件,防止虚假唤醒 -
notifyAll()是必须的——因为无法确定哪个线程该被唤醒,只用notify()可能唤醒错人导致死锁 - 所有对
current的读写、wait()/notifyAll()都需在同一个对象锁内完成
用 ReentrantLock + Condition 实现更精确唤醒
相比 synchronized,Lock 支持多个 Condition,可为每个线程创建专属等待队列(如 condA、condB、condC)。这样每次只需唤醒下一个线程对应的 Condition,避免无谓竞争,效率更高、逻辑更清晰。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- A 线程打印完 →
condB.signal() - B 线程打印完 →
condC.signal() - C 线程打印完 →
condA.signal() - 每个线程启动时先
await()自己的 condition,被 signal 后才继续
用 AtomicInteger + 自旋(适合简单场景,慎用)
借助 AtomicInteger 做状态计数(如 0→A, 1→B, 2→C, 3→A…),各线程用 get() 读当前值,通过取模判断是否轮到自己;若不是,短暂 Thread.yield() 或小延时再重试。这种方式无锁、无阻塞,但会空转消耗 CPU,仅适用于打印次数少、实时性要求高且线程数极少的演示场景。
立即学习“Java免费学习笔记(深入)”;
- 不推荐生产环境使用,尤其在高并发或低优先级线程多时容易饿死
- 必须配合
volatile或原子操作保证可见性 - 需设置终止条件(如打印 10 轮后退出),否则可能无限自旋
补充:用 Semaphore 控制通行权
初始化三个信号量:semA = new Semaphore(1)(A 先行),semB = new Semaphore(0),semC = new Semaphore(0)。A 打印后 semB.release(),B 打印后 semC.release(),C 打印后 semA.release()。每个线程开始前先 acquire() 对应信号量,天然形成串行链路。
- 语义清晰,不易出错,适合教学和中等复杂度场景
- 注意避免因异常导致信号量未释放,建议用 try-finally 包裹
- 比 wait/notify 更易理解,但底层仍依赖同步机制


















