在 Java 的 CountDownLatch 中,latch.await() 是一个关键方法,它的作用是让当前线程等待,直到 CountDownLatch 的计数器(count)变为 0。如果计数器已经为 0,则调用 await() 的线程会立即返回,不会阻塞。
核心原理
• 阻塞等待:当调用 await() 时,当前线程会进入阻塞状态,直到 CountDownLatch 的计数器被其他线程通过 countDown() 方法减少到 0。
• 非阻塞情况:如果计数器已经为 0,则 await() 立即返回,线程不会阻塞。
代码示例
import java.util.concurrent.CountDownLatch;
public class LatchExample {
public static void main(String[] args) {
// 初始化 CountDownLatch,初始计数为 1(表示等待 B 线程完成)
CountDownLatch latch = new CountDownLatch(1);
// 创建 B 线程(生产者)
Thread B = new Thread(() -> {
System.out.println("B 线程正在执行...");
// 模拟耗时操作
try { Thread.sleep(2000); } catch (InterruptedException e) {}
System.out.println("B 线程执行完毕,触发 CountDownLatch");
latch.countDown(); // 计数器减 1 → 变为 0
});
// 创建 C 线程(消费者,依赖 B 的结果)
Thread C = new Thread(() -> {
try {
System.out.println("C 线程开始等待 B 线程完成...");
latch.await(); // 阻塞直到计数器为 0
System.out.println("C 线程继续执行,B 已完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("C 线程被中断");
}
});
B.start();
C.start();
}
}
关键点
- 阻塞与唤醒:
• C 线程调用 latch.await() 后,会立即阻塞,直到 B 线程执行 latch.countDown() 将计数器减到 0。
• 当 countDown() 使计数器变为 0 时,所有等待的线程(如 C 线程)会被唤醒,继续执行。 - 线程安全:
• CountDownLatch 是线程安全的,多个线程可以同时调用 countDown() 和 await()。 - 异常处理:
• await() 可能抛出 InterruptedException,表示线程在等待时被中断。需要捕获异常或声明抛出。 - 应用场景:
• 当某个线程需要等待一个或多个线程完成任务后才能继续执行时,CountDownLatch 是常用工具。例如:
• 等待所有数据加载完成后再启动业务逻辑。
• 等待某个初始化任务完成后执行后续操作。
与 join() 的区别
• join():是 Thread 类的方法,用于等待单个线程执行完毕。例如 B.join() 表示等待 B 线程完成。
• CountDownLatch:更灵活,可以等待多个线程(通过调整初始计数),且支持更复杂的控制逻辑(例如多个线程协作完成任务)。
注意事项
• CountDownLatch 是一次性的,计数器只能从初始值递减到 0,无法重新设置。
• 如果需要可重置的计数器,可以考虑使用 CyclicBarrier。
通过 latch.await(),可以轻松实现线程间的依赖关系,确保 C 线程在 B 线程完成后再执行。

1638

被折叠的 条评论
为什么被折叠?



