在 Java 中控制多个线程的执行顺序是一个常见的需求,尤其是在实现特定业务逻辑或算法时。有多种方式可以实现对线程执行顺序的控制,以下是几种常用的方法:
1. 使用 join()
方法
Thread.join()
方法允许一个线程等待另一个线程完成其执行之后再继续。这可以用来控制线程的执行顺序。
示例:
public class JoinExample {
public static void main(String[] args) throws InterruptedException {
Thread threadA = new Thread(() -> System.out.println("Thread A is running"));
Thread threadB = new Thread(() -> {
try {
threadA.join(); // 等待 threadA 执行完毕
System.out.println("Thread B is running");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
threadA.start();
threadB.start();
}
}
2. 使用 CountDownLatch
CountDownLatch
是一个同步辅助类,它允许一个或多个线程一直等待,直到其他线程执行的一组操作完成为止。
示例:
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
Thread threadA = new Thread(() -> {
System.out.println("Thread A is running");
latch.countDown(); // 减少计数
});
Thread threadB = new Thread(() -> {
try {
latch.await(); // 等待计数归零
System.out.println("Thread B is running");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
threadB.start(); // 注意:先启动 threadB
threadA.start(); // 再启动 threadA
}
}
3. 使用 CyclicBarrier
CyclicBarrier
是一个可重复使用的屏障,它允许多个线程互相等待直到所有线程都到达某个公共屏障点。
示例:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(2, () -> System.out.println("Both threads have arrived at the barrier"));
Thread threadA = new Thread(() -> {
System.out.println("Thread A is running");
try {
barrier.await(); // 在屏障处等待
} catch (InterruptedException | BrokenBarrierException e) {
Thread.currentThread().interrupt();
}
});
Thread threadB = new Thread(() -> {
System.out.println("Thread B is running");
try {
barrier.await(); // 在屏障处等待
} catch (InterruptedException | BrokenBarrierException e) {
Thread.currentThread().interrupt();
}
});
threadA.start();
threadB.start();
}
}
4. 使用 Lock
和 Condition
通过使用显式锁(如 ReentrantLock
)和条件变量(Condition
),可以更灵活地控制线程间的协作。
示例:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockConditionExample {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void methodA() {
lock.lock();
try {
System.out.println("Method A is running");
condition.signalAll(); // 唤醒其他等待的线程
} finally {
lock.unlock();
}
}
public void methodB() throws InterruptedException {
lock.lock();
try {
condition.await(); // 等待被唤醒
System.out.println("Method B is running after being notified");
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
LockConditionExample example = new LockConditionExample();
Thread threadA = new Thread(example::methodA);
Thread threadB = new Thread(() -> {
try {
example.methodB();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
threadB.start(); // 先启动 threadB,让它等待
Thread.sleep(100); // 确保 threadB 先于 threadA 运行
threadA.start(); // 启动 threadA 并触发通知
}
}
总结
join()
最适合简单的线程顺序控制。CountDownLatch
对于一次性事件的同步非常有用。CyclicBarrier
提供了循环利用的屏障机制,适用于需要多次同步的场景。Lock
和Condition
提供了更加灵活的线程间通信手段,能够实现复杂的同步逻辑。
选择哪种方法取决于具体的应用场景以及你需要达到的具体效果。
THE END