上一篇
在Java中轮流执行两个线程可通过synchronized配合wait/notify机制实现:共享同一监视器锁,线程执行后主动等待并唤醒对方,严格交替运行,也可用ReentrantLock与双Condition精确控制切换,确保线程间顺序协作。
在Java中实现两个线程轮流执行(交替运行)的核心在于线程间通信与同步,以下是几种专业、高效且符合生产环境标准的实现方案,每种方案附带完整代码示例和原理解析:
使用 synchronized + wait()/notify()(经典方案)
通过共享对象的监视器锁控制线程执行顺序:
public class TurnTakingWithWaitNotify {
private static final Object lock = new Object();
private static boolean isThreadATurn = true; // 控制标志
public static void main(String[] args) {
Runnable taskA = () -> {
try {
synchronized (lock) {
for (int i = 0; i < 5; i++) {
while (!isThreadATurn) lock.wait(); // 非A的回合则等待
System.out.println("Thread-A: " + i);
isThreadATurn = false;
lock.notifyAll(); // 唤醒B
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
Runnable taskB = () -> {
try {
synchronized (lock) {
for (int i = 0; i < 5; i++) {
while (isThreadATurn) lock.wait(); // 非B的回合则等待
System.out.println("Thread-B: " + i);
isThreadATurn = true;
lock.notifyAll(); // 唤醒A
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
new Thread(taskA).start();
new Thread(taskB).start();
}
}
原理:

- 共享锁
lock作为同步监视器。 - 布尔标志
isThreadATurn决定当前轮到哪个线程。 wait()释放锁并挂起线程,notifyAll()唤醒等待线程。- 严格交替:A执行 → 唤醒B → B执行 → 唤醒A → 循环。
使用 ReentrantLock + Condition(高性能方案)
利用显式锁的精准唤醒机制,避免无效竞争:
import java.util.concurrent.locks.*;
public class TurnTakingWithReentrantLock {
private static final ReentrantLock lock = new ReentrantLock();
private static final Condition conditionA = lock.newCondition();
private static final Condition conditionB = lock.newCondition();
private static boolean isThreadATurn = true;
public static void main(String[] args) {
Runnable taskA = () -> {
lock.lock();
try {
for (int i = 0; i < 5; i++) {
while (!isThreadATurn) conditionA.await();
System.out.println("Thread-A: " + i);
isThreadATurn = false;
conditionB.signal(); // 精准唤醒B
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
};
Runnable taskB = () -> {
lock.lock();
try {
for (int i = 0; i < 5; i++) {
while (isThreadATurn) conditionB.await();
System.out.println("Thread-B: " + i);
isThreadATurn = true;
conditionA.signal(); // 精准唤醒A
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
};
new Thread(taskA).start();
new Thread(taskB).start();
}
}
优势:

- 精确控制唤醒目标(
signal()替代notifyAll()),减少无效线程竞争。 - 更高的并发性能(JDK推荐替代
synchronized的方案)。
使用 Semaphore(信号量方案)
通过两个信号量控制执行权限:
import java.util.concurrent.Semaphore;
public class TurnTakingWithSemaphore {
private static final Semaphore semaphoreA = new Semaphore(1); // A先执行
private static final Semaphore semaphoreB = new Semaphore(0);
public static void main(String[] args) {
Runnable taskA = () -> {
try {
for (int i = 0; i < 5; i++) {
semaphoreA.acquire(); // 获取A的许可
System.out.println("Thread-A: " + i);
semaphoreB.release(); // 释放B的许可
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
Runnable taskB = () -> {
try {
for (int i = 0; i < 5; i++) {
semaphoreB.acquire(); // 获取B的许可
System.out.println("Thread-B: " + i);
semaphoreA.release(); // 释放A的许可
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
new Thread(taskA).start();
new Thread(taskB).start();
}
}
原理:

- 初始化:A有1个许可(可执行),B有0个许可(阻塞)。
- A执行 → 释放B的许可 → B执行 → 释放A的许可 → 循环。
️ 关键注意事项
- 避免死锁:
- 确保每个
wait()/await()都有对应的唤醒。 - 锁释放:在
finally块中释放显式锁(ReentrantLock)。
- 确保每个
- 性能考量:
- 轻量级场景用
synchronized,高并发场景用ReentrantLock。 - 信号量适用于多阶段复杂同步。
- 轻量级场景用
- 线程中断处理:
- 捕获
InterruptedException并恢复中断状态(Thread.currentThread().interrupt())。
- 捕获
- 可见性保证:
- 共享变量(如
isThreadATurn)需用volatile修饰(或通过锁保证可见性)。
- 共享变量(如
总结建议
| 方案 | 适用场景 | 性能 | 复杂度 |
|---|---|---|---|
synchronized + 等待通知 |
简单交替逻辑 | 中等 | |
ReentrantLock + Condition |
高并发、精准控制 | 高 | |
Semaphore |
多许可控制(如超过2个线程轮流) | 中等 |
推荐选择:
- 新手优先使用
synchronized方案(简洁安全)。- 生产环境推荐
ReentrantLock+Condition(性能最优)。
引用说明:
- Java并发模型基于《Java并发编程实战》(Brian Goetz等)。
ReentrantLock设计参考Oracle官方文档Java 17 Lock API。- 线程同步原则遵循JLS(Java语言规范)第17章内存模型。
