上一篇                     
               
			  Java两个线程怎么轮流执行?
- 后端开发
- 2025-06-08
- 4582
 在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章内存模型。
 
  
			 
			 
			 
			 
			 
			