写一篇完整的5000字的Markdown格式文章需要一定的篇幅,所以我将为你提供一个结构化的框架和内容概要,帮助你理解并快速生成这篇文章。文章的核心内容会涵盖CountDownLatch
的基本概念、原理、源码分析以及常见使用场景,并通过实际代码案例进行讲解。以下是文章的大纲和核心部分。
JUC CountDownLatch 源码详解
目录
简介
在Java并发编程中,CountDownLatch
是一个非常重要的同步工具类,它能够帮助我们处理线程间的等待与协调。它属于java.util.concurrent
包,在多线程环境中经常用来实现某些线程的等待,直到其他线程完成特定任务。
本文将详细分析CountDownLatch
的基本使用、源码实现、常见的应用场景,并通过具体的代码实例进行说明。
CountDownLatch 基本概念
什么是 CountDownLatch
CountDownLatch
是一个同步工具类,允许一个或多个线程一直等待,直到其他线程执行完毕后才继续执行。它通过一个计数器来控制线程的等待与释放。计数器的初始值表示等待的线程数,每次countDown()
调用时,计数器减一;当计数器的值为0时,所有等待的线程会被释放。
CountDownLatch 的工作原理
- 初始化:
CountDownLatch
在创建时需要指定一个初始的计数值,通常是需要等待的线程数目。 - 等待:调用
await()
方法的线程会进入等待状态,直到计数器的值变为0。 - 倒计数:在其他线程中通过调用
countDown()
方法来减少计数器的值。 - 释放:当计数器值为0时,所有等待的线程会被释放,继续执行后续任务。
CountDownLatch 源码解析
类结构
CountDownLatch
类实现了java.io.Serializable
接口,并且有一个重要的成员变量:count
,表示当前的倒计时。
javaCopy Codepublic class CountDownLatch {
private final Sync sync;
public CountDownLatch(int count) {
if (count < 0)
throw new IllegalArgumentException("count < 0");
sync = new Sync(count);
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public void countDown() {
sync.releaseShared(1);
}
public long getCount() {
return sync.getCount();
}
private static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1L;
Sync(int count) {
setState(count);
}
protected int tryAcquireShared(int ignore) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int ignore) {
for (;;) {
int current = getState();
if (current == 0)
return false;
int next = current - 1;
if (compareAndSetState(current, next))
return next == 0;
}
}
public long getCount() {
return getState();
}
}
}
关键方法分析
- 构造方法
CountDownLatch(int count)
:初始化时传入一个正整数表示需要等待的线程数目。 await()
方法:调用该方法的线程会阻塞,直到计数器为0才会被释放。countDown()
方法:该方法会减少计数器的值,调用时会释放一个等待的线程。当计数器为0时,所有等待的线程将被唤醒。getCount()
方法:返回当前计数器的值,即剩余的等待线程数。
同步原理
CountDownLatch
内部依赖于AbstractQueuedSynchronizer
(AQS)来实现线程的同步。Sync
类继承自AQS
,并重写了两个关键方法:
tryAcquireShared(int ignore)
:当计数器为0时,返回1表示线程可以继续执行。tryReleaseShared(int ignore)
:每次调用countDown()
时,减少计数器的值,并判断是否所有线程都已被释放。
AQS的实现使用了CAS(Compare And Swap)机制,保证了多线程环境中的安全性和高效性。
CountDownLatch 使用场景与实例
常见使用场景
CountDownLatch
主要用于以下几种场景:
- 并行任务等待:当多个线程并行执行某些任务,主线程需要等待所有线程完成任务后才能继续执行后续操作。
- 线程协调:当需要等待多个线程完成某个操作后再继续执行时,
CountDownLatch
非常适合。 - 实现线程启动的同步:多个线程准备好后,一起开始执行某个任务。
实际案例分析
场景 1:多个任务并行执行,主线程等待
假设我们有多个任务需要并行执行,主线程需要等所有任务执行完后再执行下一步操作。我们可以使用CountDownLatch
来实现这个场景。
javaCopy Codepublic 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++) {
new Thread(new Task(latch)).start();
}
// 主线程等待所有任务完成
latch.await();
System.out.println("All tasks are finished, proceeding with main task.");
}
}
class Task implements Runnable {
private final CountDownLatch latch;
public Task(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " is doing its work.");
Thread.sleep(1000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
latch.countDown(); // 任务完成,减少计数器
}
}
}
在这个例子中,主线程会等待latch.await()
,直到所有的子线程完成它们的任务并调用latch.countDown()
。
场景 2:线程启动同步
有时候,我们希望多个线程在某一时刻一起启动,可以使用CountDownLatch
来实现线程启动的同步。
javaCopy Codepublic class ThreadStartSyncExample {
public static void main(String[] args) throws InterruptedException {
int threadCount = 5;
CountDownLatch latch = new CountDownLatch(1); // 只有一个计数器
// 创建多个线程,所有线程等待主线程发信号
for (int i = 0; i < threadCount; i++) {
new Thread(new Worker(latch)).start();
}
// 主线程发出信号,所有线程开始执行
System.out.println("Main thread signaling workers to start...");
latch.countDown();
}
}
class Worker implements Runnable {
private final CountDownLatch latch;
public Worker(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try {
latch.await(); // 等待主线程的信号
System.out.println(Thread.currentThread().getName() + " started working!");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
在这个示例中,主线程通过调用latch.countDown()
向所有子线程发送信号,子线程通过调用latch.await()
来等待主线程的信号,然后才开始工作。
总结与优化建议
总结
CountDownLatch
是一个非常实用的同步工具类,用于在多线程编程中控制线程之间的协调与等待。- 它通过计数器机制让线程能够等待特定条件,直到其他线程完成任务。
- 适用于并行任务等待、线程启动同步等多种场景。
优化建议
- 在高并发场景下,避免