1. CountDownLatch - 等待所有子任务完成
特点:
✅ 一次性,不能重用。
✅ 适用于主线程等待所有子线程完成任务。
✅ 子线程完成任务后调用 countDown()
递减计数,主线程 await()
等待计数变为 0 后继续执行。
示例:
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
int taskCount = 3;
CountDownLatch latch = new CountDownLatch(taskCount);
for (int i = 0; i < taskCount; i++) {
final int taskId = i;
new Thread(() -> {
System.out.println("任务 " + taskId + " 开始执行...");
try {
Thread.sleep((long) (Math.random() * 2000)); // 模拟任务执行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务 " + taskId + " 完成!");
latch.countDown(); // 任务完成,计数器 -1
}).start();
}
System.out.println("等待所有任务完成...");
latch.await(); // 阻塞,直到 countDown 变为 0
System.out.println("所有任务已完成,主线程继续执行!");
}
}
输出示例:
任务 0 开始执行...
任务 1 开始执行...
任务 2 开始执行...
等待所有任务完成...
任务 1 完成!
任务 0 完成!
任务 2 完成!
所有任务已完成,主线程继续执行!
2. CyclicBarrier - 线程到达屏障后同步执行
特点:
✅ 可以重用,多个线程到达屏障后一起继续执行。
✅ 所有线程都要 await()
,才能一起继续。
✅ 可指定 barrierAction
作为回调,在所有线程到达时执行额外任务。
示例:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
int numThreads = 3;
CyclicBarrier barrier = new CyclicBarrier(numThreads, () -> {
System.out.println(">>> 所有线程已到达屏障,执行 BarrierAction <<<");
});
for (int i = 0; i < numThreads; i++) {
final int threadId = i;
new Thread(() -> {
System.out.println("线程 " + threadId + " 准备执行任务...");
try {
Thread.sleep((long) (Math.random() * 2000)); // 模拟任务执行
System.out.println("线程 " + threadId + " 到达屏障点,等待其他线程...");
barrier.await(); // 等待所有线程到达屏障
System.out.println("线程 " + threadId + " 继续执行!");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
输出示例:
线程 0 准备执行任务...
线程 1 准备执行任务...
线程 2 准备执行任务...
线程 2 到达屏障点,等待其他线程...
线程 0 到达屏障点,等待其他线程...
线程 1 到达屏障点,等待其他线程...
>>> 所有线程已到达屏障,执行 BarrierAction <<<
线程 1 继续执行!
线程 2 继续执行!
线程 0 继续执行!
3. Phaser - 多阶段同步
特点:
✅ 可重用,支持多阶段。
✅ 支持动态增加或减少线程,比 CountDownLatch
和 CyclicBarrier
更灵活。
✅ 每个阶段线程不同,arriveAndAwaitAdvance()
进入下一个阶段。
示例:
import java.util.concurrent.Phaser;
public class PhaserExample {
public static void main(String[] args) {
Phaser phaser = new Phaser(1); // 注册主线程
for (int i = 0; i < 3; i++) {
phaser.register(); // 动态增加线程
final int threadId = i;
new Thread(() -> {
System.out.println("线程 " + threadId + " 开始执行阶段 1...");
phaser.arriveAndAwaitAdvance(); // 等待所有线程完成阶段 1
System.out.println("线程 " + threadId + " 进入阶段 2...");
phaser.arriveAndAwaitAdvance(); // 等待所有线程完成阶段 2
System.out.println("线程 " + threadId + " 进入阶段 3...");
phaser.arriveAndDeregister(); // 线程完成所有阶段,注销
}).start();
}
while (!phaser.isTerminated()) {
int phase = phaser.getPhase();
System.out.println("主线程等待第 " + phase + " 阶段完成...");
phaser.arriveAndAwaitAdvance(); // 控制主线程进入下一个阶段
}
System.out.println("所有阶段完成,主线程退出!");
}
}
输出示例:
线程 0 开始执行阶段 1...
线程 1 开始执行阶段 1...
线程 2 开始执行阶段 1...
主线程等待第 0 阶段完成...
线程 0 进入阶段 2...
线程 1 进入阶段 2...
线程 2 进入阶段 2...
主线程等待第 1 阶段完成...
线程 0 进入阶段 3...
线程 1 进入阶段 3...
线程 2 进入阶段 3...
主线程等待第 2 阶段完成...
所有阶段完成,主线程退出!
4. 选择指南
需求 | 推荐方案 |
---|---|
让主线程等待所有子任务完成后再执行 | ✅ CountDownLatch |
让一批线程同步后一起执行下一步 | ✅ CyclicBarrier |
任务有多个阶段,每个阶段线程可能不同 | ✅ Phaser |
任务不可重复,只执行一次 | ✅ CountDownLatch |
任务需要循环多次执行 | ✅ CyclicBarrier |
线程数动态变化 | ✅ Phaser |