引言
CountDownLatch是Java并发编程中一个重要的同步工具,它能够使一个或多个线程等待其他线程完成各自的工作。本文将深入分析CountDownLatch的源码实现,探讨其内部原理和实际应用场景,帮助开发者更好地理解和使用这个工具类。
一、CountDownLatch基本原理
CountDownLatch的核心思想是通过一个计数器来实现线程间的协调。当创建CountDownLatch实例时,需要指定一个初始计数值。线程可以调用await()方法等待计数器降为零,而其他线程可以通过调用countDown()方法减少计数。这种机制使得CountDownLatch成为处理线程间等待与通知的有效工具。
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
// 创建CountDownLatch实例,初始计数为3
CountDownLatch latch = new CountDownLatch(3);
// 启动三个工作线程
for (int i = 0; i < 3; i++) {
int finalI = i;
new Thread(() -> {
try {
Thread.sleep(1000); // 模拟任务执行
System.out.println("Worker " + finalI + " 完成任务");
latch.countDown(); // 减少计数
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
// 主线程等待所有工作线程完成
latch.await();
System.out.println("所有工作线程已完成任务");
}
}
二、源码结构分析
CountDownLatch的实现依赖于AbstractQueuedSynchronizer(AQS)。通过继承AQS,CountDownLatch能够利用AQS提供的强大同步机制。在源码中,CountDownLatch通过内部类Sync扩展AQS,实现了所需的同步语义。
public class CountDownLatchAnalysis {
/**
* CountDownLatch的核心源码结构
*/
private static class Sync extends AbstractQueuedSynchronizer {
// 构造函数设置初始状态(计数值)
Sync(int count) {
setState(count);
}
// 获取当前计数
int getCount() {
return getState();
}
// 实现tryAcquireShared方法
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
// 实现tryReleaseShared方法
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c - 1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
}
三、await方法实现分析
await方法是CountDownLatch的关键方法之一,它使调用线程进入等待状态,直到计数器降为零。源码中的await方法通过AQS的共享模式实现线程同步。当计数器不为零时,调用线程会被加入AQS的等待队列。
public class AwaitMethodAnalysis {
public static void explainAwaitImplementation() {
/**
* await方法的核心实现逻辑:
* 1. 尝试获取共享锁
* 2. 如果获取失败,将线程加入等待队列
* 3. 等待被其他线程唤醒
*/
CountDownLatch latch = new CountDownLatch(2);
try {
// await方法实际调用AQS的acquireSharedInterruptibly
latch.await(); // 相当于sync.acquireSharedInterruptibly(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// await方法支持超时机制
public static void awaitWithTimeout() {
CountDownLatch latch = new CountDownLatch(2);
try {
// 设置等待超时时间
boolean completed = latch.await(5, TimeUnit.SECONDS);
if (!completed) {
System.out.println("等待超时,任务未完成");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
四、countDown方法实现分析
countDown方法用于减少计数器的值,当计数器降为零时,所有等待的线程都会被唤醒。这个方法的实现使用了AQS的释放共享锁机制,确保线程安全的计数器递减和线程唤醒操作。
public class CountDownMethodAnalysis {
public static void explainCountDownImplementation() {
/**
* countDown方法的实现原理:
* 1. 通过CAS操作减少计数器值
* 2. 如果计数器降为零,唤醒所有等待线程
*/
CountDownLatch latch = new CountDownLatch(1);
// 示例:多线程调用countDown
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " 调用countDown");
latch.countDown(); // 实际调用sync.releaseShared(1)
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}, "Thread-" + i).start();
}
}
}
五、实际应用场景分析
CountDownLatch在实际开发中有着广泛的应用场景。它常用于实现并行任务的协调、等待服务启动完成、测试框架等场景。以下是一个模拟多服务启动协调的示例。
public class CountDownLatchUsage {
public static class ServiceStarter {
private final CountDownLatch latch;
private final List<String> services;
public ServiceStarter(List<String> services) {
this.services = services;
this.latch = new CountDownLatch(services.size());
}
public void startServices() {
// 并行启动所有服务
for (String service : services) {
new Thread(() -> {
try {
System.out.println("正在启动服务: " + service);
// 模拟服务启动过程
Thread.sleep((long) (Math.random() * 2000));
System.out.println("服务已启动: " + service);
latch.countDown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
public void waitForServicesStart() throws InterruptedException {
latch.await();
System.out.println("所有服务已启动完成");
}
}
}
总结
通过深入分析CountDownLatch的源码实现,我们可以看到它是如何基于AQS框架实现线程同步的。CountDownLatch的设计简洁而强大,能够有效地解决多线程协调问题。在实际开发中,理解CountDownLatch的内部实现原理对于正确使用这个工具类至关重要。也要注意CountDownLatch是一次性的,计数器归零后就不能再重用,这一特性需要在设计系统时充分考虑。对于需要重复使用的场景,可以考虑使用CyclicBarrier等其他同步工具。通过合理使用CountDownLatch,可以更好地实现复杂的并发控制逻辑,提升系统的可靠性和性能。