线程轮流执行的基本概念
在Java中,实现两个线程轮流执行是一个常见的多线程编程问题,核心目标是让两个线程按照预定顺序交替执行任务,例如线程1执行一次,然后线程2执行一次,如此循环往复,这种需求在生产环境中很常见,比如生产者-消费者模型、任务调度系统等,要实现这种轮流执行机制,需要合理运用Java提供的线程同步机制,确保线程之间的协调和通信。

使用synchronized关键字实现线程轮流
synchronized是Java中最基本的同步机制,可以通过共享变量和锁来实现线程轮流,具体步骤如下:
-
定义共享变量:创建一个共享的标志变量,用于记录当前应该执行哪个线程,可以定义一个int类型的变量,初始值为0,表示线程1先执行。
-
使用synchronized同步块:在每个线程的执行逻辑中,使用synchronized同步块来确保对共享变量的互斥访问。
-
控制执行顺序:通过条件判断来决定线程是否执行,如果当前线程不是轮到自己执行,则调用wait()方法等待;执行完成后,通知其他线程。
示例代码如下:
public class Thread轮流 {
private static int flag = 0; // 0表示线程1执行,1表示线程2执行
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
synchronized (Thread轮流.class) {
while (flag != 0) {
try {
Thread轮流.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程1执行:" + i);
flag = 1;
Thread轮流.class.notifyAll();
}
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
synchronized (Thread轮流.class) {
while (flag != 1) {
try {
Thread轮流.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程2执行:" + i);
flag = 0;
Thread轮流.class.notifyAll();
}
}
});
thread1.start();
thread2.start();
}
}
使用Lock和Condition实现更灵活的控制
除了synchronized,Java还提供了Lock接口和Condition接口,可以实现更灵活的线程控制,相比synchronized,Lock支持更复杂的锁操作,比如可中断的锁获取、尝试获取锁等。
-
创建ReentrantLock实例:创建一个可重入锁,并获取两个Condition对象,分别用于控制两个线程的等待和唤醒。

-
使用Condition的await和signal方法:在需要等待时调用await()方法,在需要唤醒其他线程时调用signal()方法。
示例代码如下:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Thread轮流Lock {
private static Lock lock = new ReentrantLock();
private static Condition condition1 = lock.newCondition();
private static Condition condition2 = lock.newCondition();
private static int flag = 0; // 0表示线程1执行,1表示线程2执行
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
lock.lock();
try {
while (flag != 0) {
condition1.await();
}
System.out.println("线程1执行:" + i);
flag = 1;
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
lock.lock();
try {
while (flag != 1) {
condition2.await();
}
System.out.println("线程2执行:" + i);
flag = 0;
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
});
thread1.start();
thread2.start();
}
}
使用BlockingQueue实现线程轮流
BlockingQueue是Java并发包中的一个接口,它支持阻塞的插入和移除操作,可以使用两个BlockingQueue来实现线程轮流执行,每个线程从自己的队列中获取任务,完成后将任务放入另一个队列。
示例代码如下:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class Thread轮流Queue {
private static BlockingQueue<String> queue1 = new LinkedBlockingQueue<>();
private static BlockingQueue<String> queue2 = new LinkedBlockingQueue<>();
public static void main(String[] args) {
queue1.add("线程1执行");
queue2.add("线程2执行");
Thread thread1 = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
String task = queue1.take();
System.out.println(task + ":" + i);
queue2.put("线程1执行");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread thread2 = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
String task = queue2.take();
System.out.println(task + ":" + i);
queue1.put("线程2执行");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread2.start();
}
}
注意事项和最佳实践
在实现线程轮流执行时,需要注意以下几点:
-
避免死锁:确保锁的获取和释放顺序一致,避免线程互相等待导致死锁。
-
处理中断异常:在调用wait()、await()等方法时,需要捕获并处理InterruptedException,确保线程能够正确响应中断。

-
使用notifyAll()而非notify():在多线程环境中,使用notifyAll()可以避免线程遗漏唤醒的问题。
-
合理设计共享变量:共享变量的设计应尽量简单,避免复杂的逻辑导致线程安全问题。
-
考虑性能影响:同步机制会带来一定的性能开销,应根据实际需求选择合适的同步方式。
实现Java中两个线程轮流执行的方法有多种,包括使用synchronized关键字、Lock和Condition接口以及BlockingQueue等,每种方法都有其适用场景和优缺点,开发者应根据具体需求选择合适的方案,在实际开发中,还需要注意线程安全、死锁避免和性能优化等问题,确保程序的稳定性和高效性,通过合理运用这些同步机制,可以有效地实现线程之间的协调和轮流执行。


















